//
// 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.