//
// FlexibleTrackManipulation.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.bom;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import visad.AnimationControl;
import visad.CellImpl;
import visad.ConstantMap;
import visad.ControlEvent;
import visad.ControlListener;
import visad.Data;
import visad.DataReferenceImpl;
import visad.DataRenderer;
import visad.DateTime;
import visad.Display;
import visad.DisplayException;
import visad.DisplayRealType;
import visad.FieldImpl;
import visad.FlatField;
import visad.FunctionType;
import visad.Integer1DSet;
import visad.Linear1DSet;
import visad.ProjectionControl;
import visad.Real;
import visad.RealTuple;
import visad.RealTupleType;
import visad.RealType;
import visad.ScalarMap;
import visad.Set;
import visad.ShapeControl;
import visad.Tuple;
import visad.TupleType;
import visad.VisADException;
import visad.VisADGeometryArray;
import visad.VisADLineArray;
import visad.VisADRay;
import visad.VisADTriangleArray;
import visad.java3d.DirectManipulationRendererJ3D;
import visad.java3d.DisplayImplJ3D;
import visad.java3d.MouseBehaviorJ3D;
import visad.java3d.TwoDDisplayRendererJ3D;
import visad.util.AnimationWidget;
/**
FlexibleTrackManipulation is the VisAD class for
manipulation of flexible storm tracks (not straight lines)
*/
public class FlexibleTrackManipulation extends Object {
private Object data_lock = new Object();
private int ntimes = 0;
private Tuple[] tuples;
private boolean[] tuple_change;
private int which_time = -1;
private Set time_set = null;
private float[] lats;
private float[] lons;
private float[] shapes;
private float[] old_lats;
private float[] old_lons;
private DataReferenceImpl track_ref;
private DataReferenceImpl[] track_refs;
private DirectManipulationRendererJ3D[] direct_manipulation_renderers;
// abcd 23 Aug 2001
private ConstantMap[][] constant_maps;
private TrackMonitor[] track_monitors;
private AnimationControl acontrol = null;
private ShapeControl shape_control1 = null;
private ShapeControl shape_control2 = null;
private ProjectionControl pcontrol = null;
private DisplayImplJ3D display;
private FieldImpl storm_track;
private FunctionType storm_track_type = null;
private DataMonitor data_monitor = null;
private int shape_index;
private int lat_index;
private int lon_index;
private float[] shapeColour; // In RGB order
private int last_time = -1;
/**
* constructor
* Uses default size of 0.1 and default cyclone symbol geometry
*/
public FlexibleTrackManipulation(DataReferenceImpl tr, DisplayImplJ3D d,
ScalarMap shape_map1, ScalarMap shape_map2,
boolean need_monitor)
throws VisADException, RemoteException
{
final float size = 0.1f;
// construct symbols
int nv = 16;
VisADGeometryArray[][] ga = makeStormShapes(nv, size);
shapeColour = new float[] {1.0f, 1.0f, 1.0f};
init(tr, d, shape_map1, shape_map2, need_monitor, size, ga);
}
/**
* Constructor - Use default cyclone shape geometry
*/
public FlexibleTrackManipulation(DataReferenceImpl tr, DisplayImplJ3D d,
ScalarMap shape_map1, ScalarMap shape_map2,
boolean need_monitor, float size)
throws VisADException, RemoteException
{
// construct symbols
int nv = 16;
VisADGeometryArray[][] ga = makeStormShapes(nv, size);
shapeColour = new float[] {1.0f, 1.0f, 1.0f};
init(tr, d, shape_map1, shape_map2, need_monitor, size, ga);
}
/**
* Construct the FTM stuff
*
* @param tr A DataReferenceImpl, The visad data for the cyclone track
* tr.getData() should have MathType: * (Time -> tuple))
* where tuple is flat [e.g., (Latitude, Longitude, shape_index)]
* and must include RealTypes Latitude and Longitude plus
* a RealType mapped to Shape in the DisplayImpl d;
* Time may or may not be mapped to Animation
*
* @param d A DisplayImplJ3D, - The Display to add the FTM to
*
* @param shape_map1 First ScalarMap of RealTypes
* in tr.getData()
*
* @param shape_map2 Second ScalarMap of RealTypes
* in tr.getData()
*
* @param need_monitor - Need to monitor tr to maintain external
* changes to it.
*
* @param size - storm symbol size
*
* @param ga A VisADGeometryArray[][] - two arrays of geometry objects
* which represent the cyclone symbols in the order:
* none, low, depresion1, depresion2, s-cyclone1, s-cyclone2,
* n-cyclone1, n-cyclone2.
* There are two arrays so you can combine shapes (ie: circle & lines)
* The geometry can be built with makeStormShapes() or an application
* defined method.
*
* @param shapeColour - colour of symbols
*
* TODO: Have a setCycloneGeometry(VisADGeometryArray[][] ga) method
*/
public FlexibleTrackManipulation(DataReferenceImpl tr, DisplayImplJ3D d,
ScalarMap shape_map1, ScalarMap shape_map2,
boolean need_monitor, float size,
VisADGeometryArray[][] ga,
float shapeColour[])
throws VisADException, RemoteException
{
this.shapeColour = shapeColour;
init(tr, d, shape_map1, shape_map2, need_monitor, size, ga);
}
/**
* Do the work to construct a FTM
*/
private void init(DataReferenceImpl tr, DisplayImplJ3D d,
ScalarMap shape_map1, ScalarMap shape_map2,
boolean need_monitor, float size,
VisADGeometryArray[][] ga)
throws VisADException, RemoteException
{
track_ref = tr;
storm_track = (FlatField) track_ref.getData();
display = d;
pcontrol = display.getProjectionControl();
ProjectionControlListener pcl = new ProjectionControlListener();
pcontrol.addControlListener(pcl);
acontrol = (AnimationControl) display.getControl(AnimationControl.class);
// use a ControlListener on Display.Animation to fake
// animation of the track
if (acontrol != null) {
AnimationControlListener acl = new AnimationControlListener();
acontrol.addControlListener(acl);
}
storm_track_type = (FunctionType) storm_track.getType();
TupleType storm_type = null;
try {
RealType time =
(RealType) storm_track_type.getDomain().getComponent(0);
if (!RealType.Time.equals(time)) {
throw new DisplayException("storm_track bad MathType: " +
time + " must be RealType.Time");
}
storm_type = (TupleType) storm_track_type.getRange();
if (!storm_type.getFlat()) {
throw new DisplayException("storm_track bad MathType: " +
storm_type + " must be flat");
}
}
catch (ClassCastException e) {
throw new DisplayException("storm_track bad MathType: " +
storm_track_type);
}
shape_index = -1;
lat_index = -1;
lon_index = -1;
Vector scalar_map_vector = display.getMapVector();
int tuple_dim = storm_type.getDimension();
RealType[] real_types = storm_type.getRealComponents();
for (int i=0; i= ntimes) {
for (int j=0; j= old_ntimes) {
track_refs[i] = new DataReferenceImpl("station_ref" + i);
track_refs[i].setData(tuples[i]);
direct_manipulation_renderers[i] =
new FTMDirectManipulationRendererJ3D(this);
// abcd 23 August 2001
ConstantMap[] foo = {
new ConstantMap(shapeColour[0], Display.Red),
new ConstantMap(shapeColour[1], Display.Green),
new ConstantMap(shapeColour[2], Display.Blue)
};
constant_maps[i] = foo;
display.addReferences(direct_manipulation_renderers[i],
track_refs[i], constant_maps[i]);
track_monitors[i] = new TrackMonitor(track_refs[i], i);
track_monitors[i].addReference(track_refs[i]);
}
else { // special && i < old_ntimes
track_refs[i] = old_track_refs[i];
direct_manipulation_renderers[i] = old_direct_manipulation_renderers[i];
constant_maps[i] = old_constant_maps[i];
track_monitors[i] = old_track_monitors[i];
}
}
}
else {
if (!special) {
track_refs = new DataReferenceImpl[1];
direct_manipulation_renderers = new DirectManipulationRendererJ3D[1];
track_monitors = new TrackMonitor[1];
constant_maps = new ConstantMap[1][];
track_refs[0] = new DataReferenceImpl("station_ref");
track_refs[0].setData(tuples[0]);
direct_manipulation_renderers[0] =
new FTMDirectManipulationRendererJ3D(this);
// abcd 23 August 2001
constant_maps[0] = new ConstantMap[] {
new ConstantMap(shapeColour[0], Display.Red),
new ConstantMap(shapeColour[1], Display.Green),
new ConstantMap(shapeColour[2], Display.Blue)
};
display.addReferences(direct_manipulation_renderers[0],
track_refs[0], constant_maps[0]);
track_monitors[0] = new TrackMonitor(track_refs[0], 0);
track_monitors[0].addReference(track_refs[0]);
}
}
} // end synchronized (data_lock)
}
private void setupTuples(FieldImpl storm_track)
throws VisADException, RemoteException {
synchronized (data_lock) {
for (int j=0; j= 0.0) shape = old_shape + 2;
}
else if (6 <= old_shape && old_shape < 8) {
if (lat < 0.0) shape = old_shape - 2;
}
Tuple old_storm = tuples[j];
if (old_storm instanceof RealTuple) {
reals = old_storm.getRealComponents();
reals[lat_index] = reals[lat_index].cloneButValue(lat);
reals[lon_index] = reals[lon_index].cloneButValue(lon);
reals[shape_index] = reals[shape_index].cloneButValue(shape);
storm = new RealTuple((RealTupleType) old_storm.getType(), reals,
((RealTuple) old_storm).getCoordinateSystem());
}
else { // old_storm instanceof Tuple
int n = old_storm.getDimension();
int k = 0;
Data[] components = new Data[n];
for (int c=0; c 0) {
amap = new ScalarMap(time, Display.Animation);
display.addMap(amap);
AnimationControl acontrol = (AnimationControl) amap.getControl();
acontrol.setStep(500);
}
FlatField ff = new FlatField(track_type, time_set);
double[][] values = new double[3][NTIMES];
for (int k=0; k= 0.0) s += 2;
}
else if (6 <= s && s < 8) {
if (values[1][k] < 0.0) s -= 2;
}
values[2][k] = s;
}
ff.setSamples(values);
DataReferenceImpl track_ref = new DataReferenceImpl("track_ref");
track_ref.setData(ff);
// create JFrame (i.e., a window) for display and slider
JFrame frame = new JFrame("test FlexibleTrackManipulation");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
// create JPanel in JFrame
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
frame.getContentPane().add(panel);
// add display to JPanel
panel.add(display.getComponent());
if (amap != null) panel.add(new AnimationWidget(amap));
FlexibleTrackManipulation ftm =
new FlexibleTrackManipulation(track_ref, display, shape_map1, shape_map2,
true, 0.05f);
JPanel button_panel = new JPanel();
button_panel.setLayout(new BoxLayout(button_panel, BoxLayout.X_AXIS));
button_panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
button_panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
EndManipFTM emf = new EndManipFTM(ftm, track_ref);
JButton end = new JButton("end manip");
end.addActionListener(emf);
end.setActionCommand("end");
button_panel.add(end);
JButton add = new JButton("add to track");
add.addActionListener(emf);
add.setActionCommand("add");
button_panel.add(add);
panel.add(button_panel);
// set size of JFrame and make it visible
frame.setSize(500, 700);
frame.setVisible(true);
}
}
class EndManipFTM implements ActionListener {
FlexibleTrackManipulation ftm;
DataReferenceImpl track_ref;
EndManipFTM(FlexibleTrackManipulation f, DataReferenceImpl tr) {
ftm = f;
track_ref = tr;
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("end")) {
try {
ftm.endManipulation();
}
catch (VisADException ex) {
}
catch (RemoteException ex) {
}
}
else if (cmd.equals("add")) {
try {
FlatField ff = (FlatField) track_ref.getData();
int ntimes = ff.getLength();
Linear1DSet time_set = (Linear1DSet) ff.getDomainSet();
Linear1DSet new_time_set =
new Linear1DSet(RealType.Time, time_set.getFirst(),
time_set.getLast() + time_set.getStep(),
ntimes + 1);
double[][] values = ff.getValues();
double[][] new_values = new double[3][ntimes + 1];
System.arraycopy(values[0], 0, new_values[0], 0, ntimes);
System.arraycopy(values[1], 0, new_values[1], 0, ntimes);
System.arraycopy(values[2], 0, new_values[2], 0, ntimes);
int k = ntimes;
new_values[0][k] = 2.0 * k - 8.0;
new_values[1][k] = 2.0 * k - 8.0;
int s = k % 8;
if (4 <= s && s < 6) {
if (new_values[1][k] >= 0.0) s += 2;
}
else if (6 <= s && s < 8) {
if (new_values[1][k] < 0.0) s -= 2;
}
new_values[2][k] = s;
FlatField new_ff = new FlatField((FunctionType) ff.getType(), new_time_set);
new_ff.setSamples(new_values);
track_ref.setData(new_ff);
}
catch (VisADException ex) {
ex.printStackTrace();
}
catch (RemoteException ex) {
ex.printStackTrace();
}
}
}
}
Ads help maintain this website.