001/*
002 * $Id: MyRubberBandBoxRendererJ3D.java,v 1.8 2011/03/24 16:06:33 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030
031//
032// MyRubberBandBoxRendererJ3D.java
033//
034
035/*
036VisAD system for interactive analysis and visualization of numerical
037data.  Copyright (C) 1996 - 2002 Bill Hibbard, Curtis Rueden, Tom
038Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
039Tommy Jasmin.
040
041This library is free software; you can redistribute it and/or
042modify it under the terms of the GNU Library General Public
043License as published by the Free Software Foundation; either
044version 2 of the License, or (at your option) any later version.
045
046This library is distributed in the hope that it will be useful,
047but WITHOUT ANY WARRANTY; without even the implied warranty of
048MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
049Library General Public License for more details.
050
051You should have received a copy of the GNU Library General Public
052License along with this library; if not, write to the Free
053Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
054MA 02111-1307, USA
055*/
056
057package edu.wisc.ssec.mcidasv.data.hydra;
058
059import java.awt.event.InputEvent;
060import java.awt.event.WindowAdapter;
061import java.awt.event.WindowEvent;
062import java.rmi.RemoteException;
063import java.util.Enumeration;
064import java.util.Vector;
065
066import javax.media.j3d.Appearance;
067import javax.media.j3d.BranchGroup;
068import javax.media.j3d.GeometryArray;
069import javax.media.j3d.Group;
070import javax.media.j3d.Shape3D;
071import javax.swing.BoxLayout;
072import javax.swing.JFrame;
073import javax.swing.JPanel;
074
075import visad.BadDirectManipulationException;
076import visad.CellImpl;
077import visad.CoordinateSystem;
078import visad.DataDisplayLink;
079import visad.DataReference;
080import visad.DataReferenceImpl;
081import visad.Display;
082import visad.DisplayImpl;
083import visad.DisplayRealType;
084import visad.DisplayTupleType;
085import visad.FlatField;
086import visad.FunctionType;
087import visad.GraphicsModeControl;
088import visad.Gridded2DSet;
089import visad.Gridded3DSet;
090import visad.Integer2DSet;
091import visad.Real;
092import visad.RealTupleType;
093import visad.RealType;
094import visad.ScalarMap;
095import visad.ScalarType;
096import visad.Set;
097import visad.ShadowType;
098import visad.Unit;
099import visad.VisADException;
100import visad.VisADLineStripArray;
101import visad.VisADRay;
102import visad.java3d.DirectManipulationRendererJ3D;
103import visad.java3d.DisplayImplJ3D;
104import visad.java3d.ShadowTypeJ3D;
105
106/**
107   RubberBandBoxRendererJ3D is the VisAD class for direct
108   manipulation of rubber band boxes
109*/
110public class MyRubberBandBoxRendererJ3D extends DirectManipulationRendererJ3D {
111
112  private RealType x = null;
113  private RealType y = null;
114  private RealTupleType xy = null;
115
116  private int mouseModifiersMask  = 0;
117  private int mouseModifiersValue = 0;
118
119  private BranchGroup branch = null;
120  private BranchGroup group  = null;
121  //- TDR
122  private boolean       keep_last_box   = false;
123  private BranchGroup   last_group      = null;
124  private GeometryArray last_geometry   = null;
125  private Appearance    last_appearance = null;
126  public Gridded3DSet   last_box        = null;
127
128  public  boolean enabled = true;
129  public  boolean active  = true;
130
131  /** this DirectManipulationRenderer is quite different - it does not
132      render its data, but only place values into its DataReference
133      on right mouse button release;
134      it uses xarg and yarg to determine spatial ScalarMaps */
135  public MyRubberBandBoxRendererJ3D (RealType xarg, RealType yarg) {
136    this(xarg, yarg, 0, 0);
137  }
138
139  /** xarg and yarg determine spatial ScalarMaps;
140      mmm and mmv determine whehter SHIFT or CTRL keys are required -
141      this is needed since this is a greedy DirectManipulationRenderer
142      that will grab any right mouse click (that intersects its 2-D
143      sub-manifold) */
144  public MyRubberBandBoxRendererJ3D (RealType xarg, RealType yarg, int mmm, int mmv) {
145    super();
146    x = xarg;
147    y = yarg;
148    mouseModifiersMask = mmm;
149    mouseModifiersValue = mmv;
150  }
151
152  /** don't render - just return BranchGroup for scene graph to
153      render rectangle into */
154  public synchronized BranchGroup doTransform()
155         throws VisADException, RemoteException {
156    branch = new BranchGroup();
157    branch.setCapability(BranchGroup.ALLOW_DETACH);
158    branch.setCapability(Group.ALLOW_CHILDREN_READ);
159    branch.setCapability(Group.ALLOW_CHILDREN_WRITE);
160    branch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
161
162    // check type and maps for valid direct manipulation
163    if (!getIsDirectManipulation()) {
164      throw new BadDirectManipulationException(getWhyNotDirect() +
165        ": DirectManipulationRendererJ3D.doTransform");
166    }
167    setBranch(branch);
168
169    if (keep_last_box) { //-TDR
170      if (last_group != null) last_group.detach();
171      branch.addChild(last_group);
172    }
173
174    return branch;
175  }
176
177  /** for use in drag_direct */
178  private transient DataDisplayLink link = null;
179  private transient DataReference ref = null;
180
181  private transient ScalarMap xmap = null;
182  private transient ScalarMap ymap = null;
183
184  float[] default_values;
185
186  /** arrays of length one for inverseScaleValues */
187  private float[] f = new float[1];
188  private float[] d = new float[1];
189  private float[] value = new float[2];
190
191  /** information calculated by checkDirect */
192  /** explanation for invalid use of DirectManipulationRenderer */
193  private String whyNotDirect = null;
194  /** dimension of direct manipulation
195      (always 2 for RubberBandBoxRendererJ3D) */
196  private int directManifoldDimension = 2;
197  /** spatial DisplayTupleType other than
198      DisplaySpatialCartesianTuple */
199  private DisplayTupleType tuple;
200  private CoordinateSystem tuplecs;
201
202  private int xindex = -1;
203  private int yindex = -1;
204  private int otherindex = -1;
205  private float othervalue;
206
207  private byte red, green, blue; // default colors
208
209  private float[][] first_x;
210  private float[][] last_x;
211  private float[][] clast_x;
212  private float cum_lon;
213
214  /** possible values for whyNotDirect */
215  private final static String xandyNotMatch =
216    "x and y spatial domains don't match";
217  private final static String xandyNotSpatial =
218    "x and y must be mapped to spatial";
219
220
221  private boolean stop = false;
222
223  public void checkDirect() throws VisADException, RemoteException {
224    setIsDirectManipulation(false);
225
226    DisplayImpl display = getDisplay();
227
228    DataDisplayLink[] Links = getLinks();
229    if (Links == null || Links.length == 0) {
230      link = null;
231      return;
232    }
233    link = Links[0];
234
235    ref = link.getDataReference();
236    default_values = link.getDefaultValues();
237
238    xmap = null;
239    ymap = null;
240    Vector scalar_map_vector = display.getMapVector();
241    Enumeration smaps = scalar_map_vector.elements();
242    while (smaps.hasMoreElements()) {
243      ScalarMap map = (ScalarMap) smaps.nextElement();
244      ScalarType real = map.getScalar();
245      if (real.equals(x)) {
246        DisplayRealType dreal = map.getDisplayScalar();
247        DisplayTupleType t = dreal.getTuple();
248        if (t != null &&
249            (t.equals(Display.DisplaySpatialCartesianTuple) ||
250             (t.getCoordinateSystem() != null &&
251              t.getCoordinateSystem().getReference().equals(
252              Display.DisplaySpatialCartesianTuple)))) {
253          xmap = map;
254          xindex = dreal.getTupleIndex();
255          if (tuple == null) {
256            tuple = t;
257          }
258          else if (!t.equals(tuple)) {
259            whyNotDirect = xandyNotMatch;
260            return;
261          }
262        }
263      }
264      if (real.equals(y)) {
265        DisplayRealType dreal = map.getDisplayScalar();
266        DisplayTupleType t = dreal.getTuple();
267        if (t != null &&
268            (t.equals(Display.DisplaySpatialCartesianTuple) ||
269             (t.getCoordinateSystem() != null &&
270              t.getCoordinateSystem().getReference().equals(
271              Display.DisplaySpatialCartesianTuple)))) {
272          ymap = map;
273          yindex = dreal.getTupleIndex();
274          if (tuple == null) {
275            tuple = t;
276          }
277          else if (!t.equals(tuple)) {
278            whyNotDirect = xandyNotMatch;
279            return;
280          }
281        }
282      }
283    }
284
285    if (xmap == null || ymap == null) {
286      whyNotDirect = xandyNotSpatial;
287      return;
288    }
289
290    xy = new RealTupleType(x, y);
291
292    // get default value for other component of tuple
293    otherindex = 3 - (xindex + yindex);
294    DisplayRealType dreal = (DisplayRealType) tuple.getComponent(otherindex);
295    int index = getDisplay().getDisplayScalarIndex(dreal);
296    othervalue = (index > 0) ? default_values[index] :
297                               (float) dreal.getDefaultValue();
298
299    // get default colors
300    index = getDisplay().getDisplayScalarIndex(Display.Red);
301    float v = (index > 0) ? default_values[index] :
302                           (float) Display.Red.getDefaultValue();
303    red = ShadowType.floatToByte(v);
304    index = getDisplay().getDisplayScalarIndex(Display.Green);
305    v = (index > 0) ? default_values[index] :
306                      (float) Display.Green.getDefaultValue();
307    green = ShadowType.floatToByte(v);
308    index = getDisplay().getDisplayScalarIndex(Display.Blue);
309    v = (index > 0) ? default_values[index] :
310                      (float) Display.Blue.getDefaultValue();
311    blue = ShadowType.floatToByte(v);
312
313    if (Display.DisplaySpatialCartesianTuple.equals(tuple)) {
314      tuple = null;
315      tuplecs = null;
316    }
317    else {
318      tuplecs = tuple.getCoordinateSystem();
319    }
320
321    directManifoldDimension = 2;
322    setIsDirectManipulation(true);
323  }
324
325  private int getDirectManifoldDimension() {
326    return directManifoldDimension;
327  }
328
329  public String getWhyNotDirect() {
330    return whyNotDirect;
331  }
332
333  public void addPoint(float[] x) throws VisADException {
334    // may need to do this for performance
335  }
336
337// methods customized from DataRenderer:
338
339  public CoordinateSystem getDisplayCoordinateSystem() {
340    return tuplecs;
341  }
342
343  /** set spatialValues from ShadowType.doTransform */
344  public synchronized void setSpatialValues(float[][] spatial_values) {
345    // do nothing
346  }
347
348  /** check if ray intersects sub-manifold */
349  public synchronized float checkClose(double[] origin, double[] direction) {
350    if (!enabled) return Float.MAX_VALUE;
351    if (!active) {
352      return Float.MAX_VALUE;
353    }
354    int mouseModifiers = getLastMouseModifiers();
355    if ((mouseModifiers & mouseModifiersMask) != mouseModifiersValue) {
356      return Float.MAX_VALUE;
357    }
358
359    try {
360      float r = findRayManifoldIntersection(true, origin, direction, tuple,
361                                            otherindex, othervalue);
362      if (r == r) {
363        return 0.0f;
364      }
365      else {
366        return Float.MAX_VALUE;
367      }
368    }
369    catch (VisADException ex) {
370      return Float.MAX_VALUE;
371    }
372  }
373
374  /** mouse button released, ending direct manipulation */
375  public synchronized void release_direct() {
376    // set data in ref
377    if (!enabled) return;
378    if (group != null) group.detach();
379    group = null;
380    try {
381      float[][] samples = new float[2][2];
382      f[0] = first_x[xindex][0];
383      d = xmap.inverseScaleValues(f);
384      d[0] = f[0];
385      samples[0][0] = (float) d[0];
386      f[0] = first_x[yindex][0];
387      d = ymap.inverseScaleValues(f);
388      d[0] = f[0];
389      samples[1][0] = (float) d[0];
390      f[0] = last_x[xindex][0];
391      d = xmap.inverseScaleValues(f);
392      d[0] = f[0];
393      samples[0][1] = (float) d[0];
394      f[0] = last_x[yindex][0];
395      d = ymap.inverseScaleValues(f);
396      d[0] = f[0];
397      samples[1][1] = (float) d[0];
398      Gridded2DSet set = new Gridded2DSet(xy, samples, 2);
399      ref.setData(set);
400      link.clearData();
401    } // end try
402    catch (VisADException e) {
403      // do nothing
404      System.out.println("release_direct " + e);
405      e.printStackTrace();
406    }
407    catch (RemoteException e) {
408      // do nothing
409      System.out.println("release_direct " + e);
410      e.printStackTrace();
411    }
412  }
413
414  public void stop_direct() {
415    stop = true;
416  }
417
418  private static final int EDGE = 20;
419
420  private static final float EPS = 0.005f;
421
422  public synchronized void drag_direct(VisADRay ray, boolean first,
423                                       int mouseModifiers) {
424    if (ref == null) return;
425    if (enabled == false) return;
426
427    if (first) {
428      stop = false;
429    }
430    else {
431      if (stop) return;
432    }
433
434    double[] origin = ray.position;
435    double[] direction = ray.vector;
436
437    try {
438      float r = findRayManifoldIntersection(true, origin, direction, tuple,
439                                            otherindex, othervalue);
440      if (r != r) {
441        if (group != null) group.detach();
442        return;
443      }
444      float[][] xx = {{(float) (origin[0] + r * direction[0])},
445                      {(float) (origin[1] + r * direction[1])},
446                      {(float) (origin[2] + r * direction[2])}};
447      if (tuple != null) xx = tuplecs.fromReference(xx);
448
449      if (first) {
450        first_x = xx;
451        cum_lon = 0.0f;
452      }
453      else if (Display.DisplaySpatialSphericalTuple.equals(tuple)) {
454        float diff = xx[1][0] - clast_x[1][0];
455        if (diff > 180.0f) diff -= 360.0f;
456        else if (diff < -180.0f) diff += 360.0f;
457        cum_lon += diff;
458        if (cum_lon > 360.0f) cum_lon -= 360.0f;
459        else if (cum_lon < -360.0f) cum_lon += 360.0f;
460      }
461      clast_x = xx;
462
463      Vector vect = new Vector();
464      f[0] = xx[xindex][0];
465      d = xmap.inverseScaleValues(f);
466
467      // WLH 31 Aug 2000
468      Real rr = new Real(x, d[0]);
469      Unit overrideUnit = xmap.getOverrideUnit();
470      Unit rtunit = x.getDefaultUnit();
471      // units not part of Time string
472      if (overrideUnit != null && !overrideUnit.equals(rtunit) &&
473          !RealType.Time.equals(x)) {
474        double dval =  overrideUnit.toThis((double) d[0], rtunit);
475        rr = new Real(x, dval, overrideUnit);
476      }   
477      String valueString = rr.toValueString();
478
479      vect.addElement(x.getName() + " = " + valueString);
480      f[0] = xx[yindex][0];
481      d = ymap.inverseScaleValues(f);
482
483      // WLH 31 Aug 2000
484      rr = new Real(y, d[0]);
485      overrideUnit = ymap.getOverrideUnit();
486      rtunit = y.getDefaultUnit();
487      // units not part of Time string
488      if (overrideUnit != null && !overrideUnit.equals(rtunit) &&
489          !RealType.Time.equals(y)) {
490        double dval =  overrideUnit.toThis((double) d[0], rtunit);
491        rr = new Real(y, dval, overrideUnit);
492      }
493      valueString = rr.toValueString();
494
495      valueString = new Real(y, d[0]).toValueString();
496      vect.addElement(y.getName() + " = " + valueString);
497      getDisplayRenderer().setCursorStringVector(vect);
498
499      float[][] xxp = {{xx[0][0]}, {xx[1][0]}, {xx[2][0]}};
500      xxp[otherindex][0] += EPS;
501      if (tuplecs != null) xxp = tuplecs.toReference(xxp);
502      float[][] xxm = {{xx[0][0]}, {xx[1][0]}, {xx[2][0]}};
503      xxm[otherindex][0] -= EPS;
504      if (tuplecs != null) xxm = tuplecs.toReference(xxm);
505      double dot = (xxp[0][0] - xxm[0][0]) * direction[0] +
506                   (xxp[1][0] - xxm[1][0]) * direction[1] +
507                   (xxp[2][0] - xxm[2][0]) * direction[2];
508      float abs = (float)
509        Math.sqrt((xxp[0][0] - xxm[0][0]) * (xxp[0][0] - xxm[0][0]) +
510                 (xxp[1][0] - xxm[1][0]) * (xxp[1][0] - xxm[1][0]) +
511                 (xxp[2][0] - xxm[2][0]) * (xxp[2][0] - xxm[2][0]));
512      float other_offset = EPS * (2.0f * EPS / abs);
513      if (dot >= 0.0) other_offset = -other_offset;
514
515      last_x =
516        new float[][] {{clast_x[0][0]}, {clast_x[1][0]}, {clast_x[2][0]}};
517      if (Display.DisplaySpatialSphericalTuple.equals(tuple) &&
518          otherindex != 1) {
519        if (last_x[1][0] < first_x[1][0] && cum_lon > 0.0f) {
520          last_x[1][0] += 360.0;
521        }
522        else if (last_x[1][0] > first_x[1][0] && cum_lon < 0.0f) {
523          last_x[1][0] -= 360.0;
524        }
525      }
526
527      int npoints = 4 * EDGE + 1;
528      float[][] c = new float[3][npoints];
529      for (int i=0; i<EDGE; i++) {
530        float a = ((float) i) / EDGE;
531        float b = 1.0f - a;
532        c[xindex][i] = b * first_x[xindex][0] + a * last_x[xindex][0];
533        c[yindex][i] = first_x[yindex][0];
534        c[otherindex][i] = first_x[otherindex][0] + other_offset;
535        c[xindex][EDGE + i] = last_x[xindex][0];
536        c[yindex][EDGE + i] = b * first_x[yindex][0] + a * last_x[yindex][0];
537        c[otherindex][EDGE + i] = first_x[otherindex][0] + other_offset;
538        c[xindex][2 * EDGE + i] = b * last_x[xindex][0] + a * first_x[xindex][0];
539        c[yindex][2 * EDGE + i] = last_x[yindex][0];
540        c[otherindex][2 * EDGE + i] = first_x[otherindex][0] + other_offset;
541        c[xindex][3 * EDGE + i] = first_x[xindex][0];
542        c[yindex][3 * EDGE + i] = b * last_x[yindex][0] + a * first_x[yindex][0];
543        c[otherindex][3 * EDGE + i] = first_x[otherindex][0] + other_offset;
544      }
545      c[0][npoints - 1] = c[0][0];
546      c[1][npoints - 1] = c[1][0];
547      c[2][npoints - 1] = c[2][0];
548      if (tuple != null) c = tuplecs.toReference(c);
549      float[] coordinates = new float[3 * npoints];
550      last_box = new Gridded3DSet(RealTupleType.SpatialCartesian3DTuple, c, npoints);
551      for (int i=0; i<npoints; i++) {
552        int i3 = 3 * i;
553        coordinates[i3] = c[0][i];
554        coordinates[i3 + 1] = c[1][i];
555        coordinates[i3 + 2] = c[2][i];
556      }
557      VisADLineStripArray array = new VisADLineStripArray();
558      array.vertexCount = npoints;
559      array.stripVertexCounts = new int[1];
560      array.stripVertexCounts[0] = npoints;
561      array.coordinates = coordinates;
562      byte[] colors = new byte[3 * npoints];
563      for (int i=0; i<npoints; i++) {
564        int i3 = 3 * i;
565        colors[i3] = red;
566        colors[i3 + 1] = green;
567        colors[i3 + 2] = blue;
568      }
569      array.colors = colors;
570      array = (VisADLineStripArray) array.adjustSeam(this);
571
572      DisplayImplJ3D display = (DisplayImplJ3D) getDisplay();
573      GeometryArray geometry = display.makeGeometry(array);
574  
575      DataDisplayLink[] Links = getLinks();
576      if (Links == null || Links.length == 0) {
577        return;
578      }
579      DataDisplayLink link = Links[0];
580
581      float[] default_values = link.getDefaultValues();
582      GraphicsModeControl mode = (GraphicsModeControl)
583        display.getGraphicsModeControl().clone();
584      float pointSize =
585        default_values[display.getDisplayScalarIndex(Display.PointSize)];
586      float lineWidth =
587        default_values[display.getDisplayScalarIndex(Display.LineWidth)];
588      mode.setPointSize(pointSize, true);
589      mode.setLineWidth(lineWidth, true);
590      Appearance appearance =
591        ShadowTypeJ3D.staticMakeAppearance(mode, null, null, geometry, false);
592
593      if (group != null) group.detach();
594      group = null;
595
596      Shape3D shape = new Shape3D(geometry, appearance);
597      group = new BranchGroup();
598      group.setCapability(Group.ALLOW_CHILDREN_READ);
599      group.setCapability(BranchGroup.ALLOW_DETACH);
600      group.addChild(shape);
601
602      //-- TDR
603      if (keep_last_box) {
604        last_group      = group;
605        last_geometry   = geometry;
606        last_appearance = appearance;
607      }
608
609      if (branch != null) branch.addChild(group);
610    } // end try
611    catch (VisADException e) {
612      // do nothing
613      e.printStackTrace();
614    }
615  }
616
617  public Object clone() {
618    return new MyRubberBandBoxRendererJ3D(x, y, mouseModifiersMask,
619                                        mouseModifiersValue);
620  }
621
622
623  //---------------------------------------------------------
624  public void setKeepLastBoxOn(boolean keep) {
625    //- default is false
626    keep_last_box = keep;
627  }
628
629  public void removeLastBox() {
630    if (last_group != null) {
631      last_group.detach();
632    }
633  }
634
635  public BranchGroup getLastBox() {
636    Shape3D shape     = new Shape3D(last_geometry, last_appearance);
637    BranchGroup group = new BranchGroup();
638    group.setCapability(Group.ALLOW_CHILDREN_READ);
639    group.setCapability(BranchGroup.ALLOW_DETACH);
640    group.addChild(shape);
641    return group;
642  }
643
644  public void setLastBox(BranchGroup box_bg) {
645    if (last_group != null) {
646      last_group.detach();
647    }
648    last_group = box_bg;
649    branch.addChild(box_bg);
650  }
651
652  public void setLastBox(MyRubberBandBoxRendererJ3D rbbr) {
653    BranchGroup box_bg = rbbr.getLastBox();
654    if (last_group != null) {
655      last_group.detach();
656    }
657    last_group = box_bg;
658    branch.addChild(box_bg);
659  }
660  //-----------------------------------------------------------
661
662
663  private static final int N = 64;
664
665  /** test RubberBandBoxRendererJ3D */
666  public static void main(String args[])
667         throws VisADException, RemoteException {
668    RealType x = RealType.getRealType("x");
669    RealType y = RealType.getRealType("y");
670    RealTupleType xy = new RealTupleType(x, y);
671
672    RealType c = RealType.getRealType("c");
673    FunctionType ft = new FunctionType(xy, c);
674
675    // construct Java3D display and mappings
676    DisplayImpl display = new DisplayImplJ3D("display1");
677    if (args.length == 0 || args[0].equals("z")) {
678      display.addMap(new ScalarMap(x, Display.XAxis));
679      display.addMap(new ScalarMap(y, Display.YAxis));
680    }
681    else if (args[0].equals("x")) {
682      display.addMap(new ScalarMap(x, Display.YAxis));
683      display.addMap(new ScalarMap(y, Display.ZAxis));
684    }
685    else if (args[0].equals("y")) {
686      display.addMap(new ScalarMap(x, Display.XAxis));
687      display.addMap(new ScalarMap(y, Display.ZAxis));
688    }
689    else if (args[0].equals("radius")) {
690      display.addMap(new ScalarMap(x, Display.Longitude));
691      display.addMap(new ScalarMap(y, Display.Latitude));
692    }
693    else if (args[0].equals("lat")) {
694      display.addMap(new ScalarMap(x, Display.Longitude));
695      display.addMap(new ScalarMap(y, Display.Radius));
696    }
697    else if (args[0].equals("lon")) {
698      display.addMap(new ScalarMap(x, Display.Latitude));
699      display.addMap(new ScalarMap(y, Display.Radius));
700    }
701    else {
702      display.addMap(new ScalarMap(x, Display.Longitude));
703      display.addMap(new ScalarMap(y, Display.Latitude));
704    }
705    display.addMap(new ScalarMap(c, Display.RGB));
706
707    Integer2DSet fset = new Integer2DSet(xy, N, N);
708    FlatField field = new FlatField(ft, fset);
709    float[][] values = new float[1][N * N];
710    int k = 0;
711    for (int i=0; i<N; i++) {
712      for (int j=0; j<N; j++) {
713        values[0][k++] = (i - N / 2) * (j - N / 2);
714      }
715    }
716    field.setSamples(values);
717    DataReferenceImpl field_ref = new DataReferenceImpl("field");
718    field_ref.setData(field);
719    display.addReference(field_ref);
720
721    Gridded2DSet dummy_set = new Gridded2DSet(xy, null, 1);
722    final DataReferenceImpl ref = new DataReferenceImpl("set");
723    ref.setData(dummy_set);
724    int m = (args.length > 1) ? InputEvent.CTRL_MASK : 0;
725    final MyRubberBandBoxRendererJ3D rbbr = new MyRubberBandBoxRendererJ3D(x,y,m,m);
726    display.addReferences(rbbr, ref);
727
728    CellImpl cell = new CellImpl() {
729      public void doAction() throws VisADException, RemoteException {
730        Set set = (Set) ref.getData();
731        float[][] samples = set.getSamples();
732        if (samples != null) {
733          System.out.println("box (" + samples[0][0] + ", " + samples[1][0] +
734                             ") to (" + samples[0][1] + ", " + samples[1][1] + ")");
735        }
736      }
737    };
738    cell.addReference(ref);
739
740    // create JFrame (i.e., a window) for display and slider
741    JFrame frame = new JFrame("test MyRubberBandBoxRendererJ3D");
742    frame.addWindowListener(new WindowAdapter() {
743      public void windowClosing(WindowEvent e) {System.exit(0);}
744    });
745
746    // create JPanel in JFrame
747    JPanel panel = new JPanel();
748    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
749    panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
750    panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
751    frame.getContentPane().add(panel);
752
753    // add display to JPanel
754    panel.add(display.getComponent());
755
756    // set size of JFrame and make it visible
757    frame.setSize(500, 500);
758    frame.setVisible(true);
759  }
760}
761