//
// CollectiveBarbManipulation.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 visad.*;
import visad.util.*;
import visad.java3d.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.*;


/**
   CollectiveBarbManipulation is the VisAD class for
   manipulation of collections of wind barbs
*/
public class CollectiveBarbManipulation extends Object {

  private FunctionType wind_field_type = null;
  private TupleType wind_type = null;
  private RealType station_index = null;
  private FunctionType wind_station_type = null;
  private RealType time = null;

  private int nindex = 0;
  private int[] ntimes;
  private Tuple[][] tuples;
  private Tuple[][] tuples2;
  private FlatField[] wind_stations;
  private Set[] time_sets;
  private double[][] times;
  private int which_time = -1;
  private int[] which_times;

  private Set time_set = null;
  private int global_ntimes = 0;
  private double[] global_times;
  private int[][] global_to_station; // [nindex][global_ntimes]
  private int[][] station_to_global; // [nindex][ntimes[i]]

  private float[] lats;
  private float[] lons;

  private DataReferenceImpl stations_ref;
  private DataReferenceImpl[] station_refs;
  private DataRenderer barb_renderer;
  private DataRenderer[] barb_manipulation_renderers;
  private BarbMonitor[] barb_monitors;

  private WindMonitor wind_monitor = null;

  private AnimationControl acontrol = null;
  private ProjectionControl pcontrol = null;

  private DisplayImplJ3D display1;
  private DisplayImplJ3D display2;
  private FieldImpl wind_field;
  private boolean absolute;
  private float inner_distance;
  private float outer_distance;
  private double inner_time;
  private double outer_time;
  private DataReference curve_ref = null;

  private boolean barbs;
  private boolean force_station;
  private boolean knots;

  private ConstantMap[] cmaps;

  private int azimuth_index;
  private int radial_index;
  private int azimuth_index2;
  private int radial_index2;
  private int lat_index;
  private int lon_index;

  private int last_sta = -1;
  private int last_time = -1;
  private int last_display = -1;
  private boolean last_curve = true;

  private float[][] azimuths;
  private float[][] radials;
  private float[][] old_azimuths;
  private float[][] old_radials;

  // data for display2
  private int station = -1;
  private DataReferenceImpl[] time_refs = null;
  private DataRenderer[] barb_manipulation_renderers2 = null;
  private BarbMonitor2[] barb_monitors2 = null;

  private Object data_lock = new Object();

  private boolean ended = false; // manipulation ended

  private int time_dir = 0; // < 0 for backward only, > 0 for forward only,
                            // == 0 for both directions

  private static final int NCIRCLE = 24;
  private DataRenderer[] circle_renderer = null;
  private DataReferenceImpl[] circle_ref = null;
  private boolean circle_enable = false;

  private Releaser releaser = null;
  private DataReferenceImpl releaser_ref = null;

  private Stepper stepper = null;
  private DataReferenceImpl stepper_ref = null;

  private boolean dzoom = false;
  private DiscoverableZoom pcl = null;

  /**
     wf should have MathType:
       (station_index -> (Time -> tuple))
     where tuple is flat
       [e.g., (Latitude, Longitude, (flow_dir, flow_speed))]
     and must include RealTypes Latitude and Longitude plus
     RealTypes mapped to Flow1Azimuth and Flow1Radial, or to
     Flow2Azimuth and Flow2Radial, in the DisplayImplJ3Ds d1
     and d2 (unless they are not null);
     d1 must have Time mapped to Animation, and d2 must not;

     abs indicates absolute or relative value adjustment
     id and od are inner and outer distances in meters
     it and ot are inner and outer times in seconds
     influence is 1.0 inside inner, 0.0 outside outer and
     linear between distance and time influences multiply;

     cms are ConstantMap's used for rendering barbs

     each time the user clicks the right mouse button to
     manipulate a wind barb, the "reference" values for all
     wind barbs are set - thus repeatedly adjusting the same
     barb will magnify its influence over its neighbors;

     sta is index of station for display2;

     need_monitor is true if wf might be changed externally
     during manipulation

     brbs is true to indicate Barb*RendererJ3D, false to
     indicate Swell*RendererJ3D

     fs is true to indicate that d2 should switch to whatever
     station is being manipulated

     kts is false to indicate no m/s to knots conversion in
     wind barb renderers

     dz is true to indicate to use DiscoverableZoom

     inner_circle_color is array of RGB colors for an inner circle
     of influence, or null for no inner circles
     inner_circle_width is the line width for the inner circle

     outer_circle_color is array of RGB colors for an outer circle
     of influence, or null for no outer circles
     outer_circle_width is the line width for the outer circle
  */
  public CollectiveBarbManipulation(FieldImpl wf,
                 DisplayImplJ3D d1, DisplayImplJ3D d2, ConstantMap[] cms,
                 boolean abs, float id, float od, float it, float ot, int sta,
                 boolean need_monitor, boolean brbs, boolean fs, boolean kts,
                 boolean dz,
                 double[] inner_circle_color, int inner_circle_width,
                 double[] outer_circle_color, int outer_circle_width)
         throws VisADException, RemoteException {
    wind_field = wf;
    display1 = d1;
    display2 = d2;
    cmaps = cms;
    absolute = abs;
    inner_distance = id;
    outer_distance = od;
    inner_time = it;
    outer_time = ot;
    curve_ref = null;
    barbs = brbs;
    force_station = fs;
    knots = kts;
    dzoom = dz;

    // station = sta; // NEW

    if (display1 == null && display2 == null) {
      throw new CollectiveBarbException("display1 and display2 cannot " +
                  "both be null");
    }

    wind_field_type = (FunctionType) wind_field.getType();
    wind_type = null;
    station_index = null;
  
    try {
      station_index =
        (RealType) wind_field_type.getDomain().getComponent(0);
      if (RealType.Time.equals(station_index)) {
        throw new CollectiveBarbException("wind_field bad MathType: " +
                     station_index + " cannot be RealType.Time");
      }
      wind_station_type = (FunctionType) wind_field_type.getRange();
      time = (RealType) wind_station_type.getDomain().getComponent(0);
      if (!RealType.Time.equals(time)) {
        throw new CollectiveBarbException("wind_field bad MathType: " +
                     time + " must be RealType.Time");
      }
      wind_type = (TupleType) wind_station_type.getRange();
      if (!wind_type.getFlat()) {
        throw new CollectiveBarbException("wind_field bad MathType: " +
                      wind_type + " must be flat");
      }
    }
    catch (ClassCastException e) {
      throw new CollectiveBarbException("wind_field bad MathType: " +
                     wind_field_type);
    }
 
    lat_index = -1;
    lon_index = -1;
    // int tuple_dim = wind_type.getDimension();
    RealType[] real_types = wind_type.getRealComponents();
    int tuple_dim = real_types.length;
    for (int i=0; i 0) ? inner_circle_width : 1;
      ConstantMap[] color_maps =
        {new ConstantMap(inner_circle_color[0], Display.Red),
         new ConstantMap(inner_circle_color[1], Display.Green),
         new ConstantMap(inner_circle_color[2], Display.Blue),
         new ConstantMap(cw, Display.LineWidth)};
      circle_ref[0] = new DataReferenceImpl("inner_circle");
      circle_ref[0].setData(null);
      circle_renderer[0] = new DefaultRendererJ3D();
      display1.addReferences(circle_renderer[0], circle_ref[0], color_maps);
      circle_renderer[0].toggle(false);
      circle_renderer[0].suppressExceptions(true);
    }
    if (display1 != null && outer_circle_color != null) {
      double cw = (outer_circle_width > 0) ? outer_circle_width : 1;
      ConstantMap[] color_maps =
        {new ConstantMap(outer_circle_color[0], Display.Red),
         new ConstantMap(outer_circle_color[1], Display.Green),
         new ConstantMap(outer_circle_color[2], Display.Blue),
         new ConstantMap(cw, Display.LineWidth)};
      circle_ref[1] = new DataReferenceImpl("outer_circle");
      circle_ref[1].setData(null);
      circle_renderer[1] = new DefaultRendererJ3D();
      display1.addReferences(circle_renderer[1], circle_ref[1], color_maps);
      circle_renderer[1].toggle(false);
      circle_renderer[1].suppressExceptions(true);
    }

    releaser_ref = new DataReferenceImpl("releaser"); // NEW
    releaser = new Releaser();
    releaser.addReference(releaser_ref);
  }


  // assumes inside synchronized (data_lock) { ... }
  private void setupData()
          throws VisADException, RemoteException {
    try {
      nindex = wind_field.getLength();
      ntimes = new int[nindex];
      tuples = new Tuple[nindex][];
      tuples2 = new Tuple[nindex][];
      which_times = new int[nindex];
      wind_stations = new FlatField[nindex];
      time_sets = new Set[nindex];
      times = new double[nindex][];
      azimuths = new float[nindex][];
      radials = new float[nindex][];
      old_azimuths = new float[nindex][];
      old_radials = new float[nindex][];
      for (int i=0; i 0), only backward
      (dir < 0), or both (dir == 0) */
  public void setTimeDir(int dir) {
    time_dir = dir;
  }

  /** set a DataReference to a curve (typically from a
      CurveManipulationRendererJ3D) to replace distance
      parameters; also set time parameters */
  public void setCollectiveCurve(boolean abs, DataReference r,
                                 float it, float ot)
         throws VisADException, RemoteException {
    absolute = abs;
    if (it < 0.0 || ot < it) {
      throw new CollectiveBarbException("outer_time must be " +
                                   "greater than inner_time");
    }
    curve_ref = r;
    inner_time = it;
    outer_time = ot;
  }

  /** called by the application to select which station is selected
      in display2 */
  public void setStation(int sta)
         throws VisADException, RemoteException {
    synchronized (data_lock) {
      if (display2 == null) {
        throw new CollectiveBarbException("display2 cannot be null");
      }
      if (sta < 0 || sta >= nindex) {
        throw new CollectiveBarbException("bad station index " + sta);
      }

      if (sta == station) return; // NEW
      station = sta;
  
      if (time_refs != null && time_refs.length != ntimes[station]) {
        int n = time_refs.length;
        for (int i=0; i 0 &&
                sets[sets.length - 1] instanceof Gridded2DSet) {
              set = (Gridded2DSet) sets[sets.length - 1];
            }
          }
          if (set != null) {
            float[][] samples = set.getSamples();
            if (DelaunayCustom.inside(samples, lat, lon) &&
                DelaunayCustom.inside(samples, lats[i], lons[i])) {
              dist_mult = 1.0;
            }
          }
        }
        catch (VisADException ex) {
          dist_mult = 0.0;
        }
      }
      else {
        double lat_diff = Math.abs(lat - lats[i]);
        double mid_lat = 0.5 * (lat + lats[i]);
        double coslat = Math.cos(Data.DEGREES_TO_RADIANS * mid_lat);
        double lon_diff = Math.abs(lon - lons[i]) * coslat;
        double dist = ShadowType.METERS_PER_DEGREE *
          Math.sqrt(lon_diff * lon_diff + lat_diff * lat_diff);
        if (dist > outer_distance) continue;
        dist_mult = (dist <= inner_distance) ? 1.0 :
          (outer_distance - dist) / (outer_distance - inner_distance);
      }
      for (int j=0; j outer_time) continue;
        double time_mult = (time_diff <= inner_time) ? 1.0 :
          (outer_time - time_diff) / (outer_time - inner_time);

        // WLH 13 July 2000
        if ((time_dir > 0 && times[i][j] < time) ||
            (time_dir < 0 && time < times[i][j])) {
          continue;
        }

        double mult = dist_mult * time_mult;
        if (i == sta_index && j == time_index) mult = 1.0;
        double azimuth_diff = 0.0;
        double radial_diff = 0.0;

        if (absolute) {
          azimuth_diff = new_azimuth - old_azimuths[i][j];
          radial_diff = new_radial - old_radials[i][j];
        }
        else {
          azimuth_diff = new_azimuth - old_azimuths[sta_index][time_index];
          radial_diff = new_radial - old_radials[sta_index][time_index];
        }
        if (azimuth_diff < -180.0) azimuth_diff += 360.0;
        if (azimuth_diff > 180.0) azimuth_diff -= 360.0;
        double azimuth = old_azimuths[i][j] + mult * (azimuth_diff);
        double radial = old_radials[i][j] + mult * (radial_diff);
        if (radial < 0.0) radial = 0.0;

        Tuple wind = modifyWind(tuples[i][j], azimuth, radial);
        Tuple wind2 = modifyWind(tuples2[i][j], azimuth, radial);

        azimuths[i][j] = (float) azimuth;
        radials[i][j] = (float) radial;
        wind_stations[i].setSample(j, wind);
        tuples[i][j] = wind;
        if (station_refs != null && j == which_times[i]) {
          station_refs[i].setData(tuples[i][j]);
// if (i == 0) System.out.println("collectiveAdjust: station " + i + " time " + j);
        }
        tuples2[i][j] = wind2;
        if (time_refs != null && i == station) {
          time_refs[j].setData(tuples2[i][j]);
        }
      } // end for (int j=0; j 360.0) azimuth -= 360.0;
      Tuple new_wind = modifyWind(wind, azimuth, radial);
      wind_stations[current_index].setSample(time_index, new_wind);
      tuples[current_index][time_index] = new_wind;
      if (station_refs != null) {
        station_refs[current_index].setData(tuples[current_index][time_index]);
// System.out.println("plusAngle: station " + current_index +
//                    " time " + time_index);
      }

    }
  }

  void minusAngle() throws VisADException, RemoteException {
    synchronized (data_lock) {
      int time_index = which_times[current_index];
      Tuple wind = tuples[current_index][time_index];
      double azimuth = azimuths[current_index][time_index];
      double radial = radials[current_index][time_index];
      azimuth -= 10;
      if (azimuth < 0.0) azimuth += 360.0;
      Tuple new_wind = modifyWind(wind, azimuth, radial);
      wind_stations[current_index].setSample(time_index, new_wind);
      tuples[current_index][time_index] = new_wind;
      if (station_refs != null) {
        station_refs[current_index].setData(tuples[current_index][time_index]);
// System.out.println("minusAngle: station " + current_index +
//                    " time " + time_index);
      }
    }
  }

  void plusSpeed() throws VisADException, RemoteException {
    synchronized (data_lock) {
      int time_index = which_times[current_index];
      Tuple wind = tuples[current_index][time_index];
      double azimuth = azimuths[current_index][time_index];
      double radial = radials[current_index][time_index];
      radial += five_knots;
      Tuple new_wind = modifyWind(wind, azimuth, radial);
      wind_stations[current_index].setSample(time_index, new_wind);
      tuples[current_index][time_index] = new_wind;
      if (station_refs != null) {
        station_refs[current_index].setData(tuples[current_index][time_index]);
// System.out.println("plusSpeed: station " + current_index +
//                    " time " + time_index);
      }
    }
  }

  void minusSpeed() throws VisADException, RemoteException {
    synchronized (data_lock) {
      int time_index = which_times[current_index];
      Tuple wind = tuples[current_index][time_index];
      double azimuth = azimuths[current_index][time_index];
      double radial = radials[current_index][time_index];
      radial -= five_knots;
      if (radial < 0.0) radial = 0.0;
      Tuple new_wind = modifyWind(wind, azimuth, radial);
      wind_stations[current_index].setSample(time_index, new_wind);
      tuples[current_index][time_index] = new_wind;
      if (station_refs != null) {
        station_refs[current_index].setData(tuples[current_index][time_index]);
// System.out.println("minusSpeed: station " + current_index +
//                    " time " + time_index);
      }
    }
  }

  void nextWind() {
    int n = nindex;
    current_index = (current_index < 0) ? 0 : (current_index + 1) % n;
  }

  void previousWind() {
    int n = nindex;
    current_index = (current_index < 0) ? n-1 : (current_index + (n-1)) % n;
  }

  class CBarbManipulationRendererJ3D extends BarbManipulationRendererJ3D {
  
    CollectiveBarbManipulation cbm;
    int index;
  
    CBarbManipulationRendererJ3D(CollectiveBarbManipulation c, int i) {
      super();
      cbm = c;
      index = i;
    }
  
    /** mouse button released, ending direct manipulation */
    public void release_direct() {
      cbm.release();
    }
  
    public void drag_direct(VisADRay ray, boolean first,
                                         int mouseModifiers) {
      if (first) {
        cbm.circleEnable();
        current_index = index;
      }
// System.out.println("CBarbManipulationRendererJ3D " + index);
      super.drag_direct(ray, first, mouseModifiers);
    }
  }
  
  class CSwellManipulationRendererJ3D extends SwellManipulationRendererJ3D {
  
    CollectiveBarbManipulation cbm;
    int index;
  
    CSwellManipulationRendererJ3D(CollectiveBarbManipulation c, int i) {
      super();
      cbm = c;
      index = i;
    }
  
    /** mouse button released, ending direct manipulation */
    public void release_direct() {
      cbm.release();
    }
  
    public void drag_direct(VisADRay ray, boolean first,
                                         int mouseModifiers) {
      if (first) {
        cbm.circleEnable();
        current_index = index;
      }
      super.drag_direct(ray, first, mouseModifiers);
    }
  }


  private static final int NSTAS = 5; // actually NSTAS * NSTAS
  private static final int NTIMES = 10;

  public static void main(String args[])
         throws VisADException, RemoteException {

    // construct RealTypes for wind record components
    RealType lat = RealType.Latitude;
    RealType lon = RealType.Longitude;
    RealTupleType earth = new RealTupleType(lat, lon);
    RealType windx = RealType.getRealType("windx",
                          CommonUnit.meterPerSecond);     
    RealType windy = RealType.getRealType("windy",
                          CommonUnit.meterPerSecond);     
    RealType red = RealType.getRealType("red");
    RealType green = RealType.getRealType("green");

    // EarthVectorType extends RealTupleType and says that its
    // components are vectors in m/s with components parallel
    // to Longitude (positive east) and Latitude (positive north)
    EarthVectorType windxy = new EarthVectorType(windx, windy);

    RealType wind_dir = RealType.getRealType("wind_dir",
                          CommonUnit.degree);
    RealType wind_speed = RealType.getRealType("wind_speed",
                          CommonUnit.meterPerSecond);
    RealTupleType windds = null;
    windds =
      new RealTupleType(new RealType[] {wind_dir, wind_speed},
      new WindPolarCoordinateSystem(windxy), null);

    RealType stn = RealType.getRealType("station");
    Set stn_set = new Integer1DSet(stn, NSTAS * NSTAS);
    RealType time = RealType.Time;
    double start = new DateTime(1999, 122, 57060).getValue();
    Set time_set = new Linear1DSet(time, start, start + 2700.0, NTIMES);
    Set time_set2 = new Linear1DSet(time, start + 150.0, start + 2850.0, NTIMES);

    TupleType tuple_type = null;
    tuple_type = new TupleType(new MathType[]
          {lon, lat, windds, red, green});

    FunctionType station_type = new FunctionType(time, tuple_type);
    FunctionType stations_type = new FunctionType(stn, station_type);

    int image_size = 128;
    RealType value = RealType.getRealType("value");
    FunctionType image_type = new FunctionType(earth, value);
    Linear2DSet image_set =
      new Linear2DSet(earth, -50.0, -30.0, image_size, -10.0, 10.0, image_size);
    FlatField image = new FlatField(image_type, image_set);
    float[][] image_values = new float[1][image_size * image_size];
    for (int i=0; i 0) ?
      new CollectiveBarbManipulation(field2, display1, display2, cmaps2, false,
                                     500000.0f, 1000000.0f, 0.0f, 1000.0f,
                                     0, false, false, true, false, true,
                                     new double[] {0.0, 0.5, 0.5}, 1,
                                     new double[] {0.5, 0.5, 0.0}, 2) :
      null;

    CollectiveBarbManipulation[] cbms = (cbm2 == null) ?
      new CollectiveBarbManipulation[] {cbm} :
      new CollectiveBarbManipulation[] {cbm, cbm2};
    DisplayRendererJ3D dr = (DisplayRendererJ3D) display1.getDisplayRenderer();
    CBMKeyboardBehaviorJ3D kbd = new CBMKeyboardBehaviorJ3D(dr);
    dr.addKeyboardBehavior(kbd);
    kbd.setWhichCBM(cbm);

    // construct invisible starter set
    Gridded2DSet set1 =
      new Gridded2DSet(earth, new float[][] {{0.0f}, {0.0f}}, 1);
    Gridded2DSet[] sets = {set1};
    UnionSet set = new UnionSet(earth, sets);
    final DataReferenceImpl set_ref = new DataReferenceImpl("set_ref");
    set_ref.setData(set);
    int mask = InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK;
    final CurveManipulationRendererJ3D cmr =
      new CurveManipulationRendererJ3D(mask, mask, true);
    display1.addReferences(cmr, set_ref);

    RealTuple rt = new RealTuple(earth, new double[] {Double.NaN, Double.NaN});
    final DataReferenceImpl point_ref = new DataReferenceImpl("point_ref");
    point_ref.setData(rt);
    final PointManipulationRendererJ3D pmr =
      new PointManipulationRendererJ3D(lat, lon, mask, mask);
    display1.addReferences(pmr, point_ref);
    pmr.toggle(false);

    // create JFrame (i.e., a window) for display and slider
    JFrame frame = new JFrame("test CollectiveBarbManipulation");
    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.X_AXIS));
    // panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
    // panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);

    JPanel display_panel = new JPanel();
    display_panel.setLayout(new BoxLayout(display_panel, BoxLayout.Y_AXIS));

    // add displays to JPanel
    JPanel panel1 = (JPanel) display1.getComponent();
    JPanel panel2 = (JPanel) display2.getComponent();
    Border etchedBorder5 =
      new CompoundBorder(new EtchedBorder(),
                         new EmptyBorder(5, 5, 5, 5));
    panel1.setBorder(etchedBorder5);
    panel2.setBorder(etchedBorder5);
    display_panel.add(panel1);
    display_panel.add(panel2);
    display_panel.setMaximumSize(new Dimension(400, 800));

    JPanel widget_panel = new JPanel();
    widget_panel.setLayout(new BoxLayout(widget_panel, BoxLayout.Y_AXIS));

    widget_panel.add(new AnimationWidget(amap));

    final DataReferenceImpl station_select_ref =
      new DataReferenceImpl("station_select_ref");
    VisADSlider station_select_slider =
      new VisADSlider("station", 0, NSTAS * NSTAS - 1, 0, 1.0,
                      station_select_ref, RealType.Generic);
    widget_panel.add(station_select_slider);
    CellImpl cell = new CellImpl() {
      public void doAction() throws VisADException, RemoteException {
        int sta = (int) ((Real) station_select_ref.getData()).getValue();
        if (0 <= sta && sta < NSTAS * NSTAS) cbm.setStation(sta);
        if (0 <= sta && sta < NSTAS * NSTAS && cbm2 != null) cbm2.setStation(sta);
      }
    };
    cell.addReference(station_select_ref);

    CellImpl cell2 = new CellImpl() {
      public void doAction() throws VisADException, RemoteException {
        UnionSet cset = (UnionSet) set_ref.getData();
        SampledSet[] csets = cset.getSets();
        if (csets.length > 0) {
          float[][] samples = csets[csets.length - 1].getSamples();
          if (samples != null && samples[0].length > 2) {
            cbm.setCollectiveCurve(false, set_ref, 0.0f, 1000.0f);
            if (cbm2 != null) cbm2.setCollectiveCurve(false, set_ref, 0.0f, 1000.0f);
          }
        }
      }
    };
    cell2.addReference(set_ref);

    final JButton add = new JButton("add");
    CellImpl cell3 = new CellImpl() {
      public void doAction() throws VisADException, RemoteException {
        RealTuple rt3 = (RealTuple) point_ref.getData();
        float lat3 = (float) ((Real) rt3.getComponent(0)).getValue();
        float lon3 = (float) ((Real) rt3.getComponent(1)).getValue();
        if (lat3 == lat3 && lon3 == lon3) {
          cbm.addStation(lat3, lon3);
          cmr.toggle(true);
          pmr.toggle(false);
          add.setText("add");
        }
      }
    };
    cell3.addReference(point_ref);

    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);

    EndManipCBM emc =
      new EndManipCBM(cbm, cbm2, set_ref, add, cmr, pmr);
    JButton end = new JButton("end manip");
    end.addActionListener(emc);
    end.setActionCommand("end");
    button_panel.add(end);
    JButton del = new JButton("delete curve");
    del.addActionListener(emc);
    del.setActionCommand("del");
    button_panel.add(del);
    add.addActionListener(emc);
    add.setActionCommand("add");
    button_panel.add(add);
    JButton dir = new JButton("time dir");
    dir.addActionListener(emc);
    dir.setActionCommand("dir");
    button_panel.add(dir);

    widget_panel.add(button_panel);
    widget_panel.setMaximumSize(new Dimension(400, 800));

    panel.add(display_panel);
    panel.add(widget_panel);
    frame.getContentPane().add(panel);

    // set size of JFrame and make it visible
    frame.setSize(800, 800);
    frame.setVisible(true);
  }
}

/** a help class for the GUI in CollectiveBarbManipulation.main() */
class EndManipCBM implements ActionListener {
  CollectiveBarbManipulation cbm;
  CollectiveBarbManipulation cbm2;
  DataReferenceImpl set_ref;
  DisplayImpl display;
  int dir = 0;
  // boolean add_mode;
  JButton add;
  CurveManipulationRendererJ3D cmr;
  PointManipulationRendererJ3D pmr;

  EndManipCBM(CollectiveBarbManipulation cb, CollectiveBarbManipulation cb2,
              DataReferenceImpl r, JButton a,
              CurveManipulationRendererJ3D cm, PointManipulationRendererJ3D p) {
    cbm = cb;
    cbm2 = cb2;
    set_ref = r;
    add = a;
    cmr = cm;
    pmr = p;
    // add_mode = false;
  }

  public void actionPerformed(ActionEvent e) {
    String cmd = e.getActionCommand();
    if (cmd.equals("end")) {
      try {
        FieldImpl final_field = cbm.endManipulation();
        FieldImpl final_field2 = (cbm2 != null) ? cbm2.endManipulation() : null;
      }
      catch (VisADException ex) {
      }
      catch (RemoteException ex) {
      }
    }
    else if (cmd.equals("del")) {
      try {
        del_curve();
      }
      catch (VisADException ex) {
        ex.printStackTrace();
      }
      catch (RemoteException ex) {
        ex.printStackTrace();
      }
    }
    else if (cmd.equals("add")) {
      try {
        // add_mode = !add_mode;
        if (add.getText().equals("add")) {
          cmr.toggle(false);
          pmr.toggle(true);
          add.setText("ready");
          del_curve();
        }
      }
      catch (VisADException ex) {
        ex.printStackTrace();
      }
      catch (RemoteException ex) {
        ex.printStackTrace();
      }
    }
    else if (cmd.equals("dir")) {
      dir = (dir == 0) ? +1 : ((dir > 0) ? -1 : 0);
      cbm.setTimeDir(dir);
      if (cbm2 != null) cbm2.setTimeDir(dir);
    }
  }

  private void del_curve()
          throws VisADException, RemoteException {
    UnionSet set = (UnionSet) set_ref.getData();
    SampledSet[] sets = set.getSets();
    int n = sets.length - 1;
    SampledSet[] new_sets = null; 
    if (n > 0) {      
      new_sets = new SampledSet[n];
      System.arraycopy(sets, 0, new_sets, 0, n);
    }
    else {
      new_sets = new SampledSet[] {new Gridded2DSet(set.getType(),
                            new float[][] {{0.0f}, {0.0f}}, 1)};
    }
    set_ref.setData(new UnionSet(set.getType(), new_sets));
    cbm.setCollectiveParameters(false, 500000.0f, 1000000.0f, 0.0f, 1000.0f);
    if (cbm2 != null) {
      cbm2.setCollectiveParameters(false, 500000.0f, 1000000.0f, 0.0f, 1000.0f);
    }
  }

}


 

Ads help maintain this website.