001/*
002 * $Id: SubsetRubberBandBox.java,v 1.11 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
031package edu.wisc.ssec.mcidasv.data.hydra;
032
033import edu.wisc.ssec.mcidasv.data.hydra.MyRubberBandBoxRendererJ3D;
034
035import ucar.visad.display.Displayable;
036import ucar.visad.display.LineDrawing;
037
038import visad.*;
039import visad.bom.*;
040
041import java.rmi.RemoteException;
042
043import java.awt.event.InputEvent;
044
045
046public class SubsetRubberBandBox extends LineDrawing {
047
048    /** x type for the box */
049    private RealType xType;
050
051    /** y type for the box */
052    private RealType yType;
053
054    /** renderer */
055    private MyRubberBandBoxRendererJ3D rubberBandBox;
056
057    /** bounds defined by the rubber band box */
058    private Gridded2DSet bounds;
059
060    /** mouse event mask */
061    private int mask;
062
063    private FlatField data;
064    private boolean isLL;
065    private boolean lastBoxOn;
066
067    private CoordinateSystem dataCS;
068
069    private CoordinateSystem displayCS;
070
071    private static int count = 0;
072
073    /**
074     * Construct a RubberBandBox using xType as the X coordinate and
075     * yType as the Y coordinate of the box.
076     *
077     * @param  xType   RealType of the X coordinate of the box
078     * @param  yType   RealType of the Y coordinate of the box
079     *
080     * @throws VisADException   VisAD error
081     * @throws RemoteException   Remote error
082     */
083    public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS)
084            throws VisADException, RemoteException {
085        this(false, data, displayCS, 0);
086    }
087
088    public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask)
089            throws VisADException, RemoteException {
090        this(false, data, displayCS, mask);
091    }
092
093    public SubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask)
094            throws VisADException, RemoteException {
095        this(isLL, data, displayCS, mask, true);
096    }
097
098    public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn)
099            throws VisADException, RemoteException {
100        this(false, data, displayCS, mask, lastBoxOn);
101    }
102
103
104
105    /**
106     * Construct a RubberBandBox using xType as the X coordinate and
107     * yType as the Y coordinate of the box.
108     *
109     * @param xType   RealType of the X coordinate of the box
110     * @param yType   RealType of the Y coordinate of the box
111     * @param mask    key mask to use for rubberbanding
112     *
113     * @throws VisADException   VisAD error
114     * @throws RemoteException   Remote error
115     */
116    public SubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn)
117            throws VisADException, RemoteException {
118        super("Subset Rubber Band Box");
119
120        this.data = data;
121        this.displayCS = displayCS;
122        this.isLL = isLL;
123        this.lastBoxOn =  lastBoxOn;
124
125        //System.out.println("\n\nSubsetRubberBandBox:");
126        //System.out.println("    isLL=" + isLL);
127        //System.out.println("    displayCS=" + displayCS.getClass());
128        //System.out.println("    mask=" + mask);
129        RealTupleType rtype = ((FunctionType)data.getType()).getDomain();
130        dataCS = rtype.getCoordinateSystem();
131        if (dataCS == null) {
132          dataCS = new GridCoordinateSystem((GriddedSet)data.getDomainSet());
133        }
134        //System.out.println("    dataCS=" + dataCS.getClass());
135
136        IdentityCoordinateSystem iCS =
137             new IdentityCoordinateSystem(
138                   new RealTupleType(new RealType[] {RealType.getRealType("ZZtop")}));
139        //System.out.println("iCS=" + iCS);
140
141        CoordinateSystem cs =
142             new CartesianProductCoordinateSystem(new CoordinateSystem[] {dataCS, iCS});
143        //System.out.println("cs=" + cs);
144
145        CoordinateSystem new_cs = new DataToDisplayCoordinateSystem(isLL, cs, displayCS);
146        //System.out.println("new_cs=" + new_cs);
147        
148
149        DisplayRealType displayLineType =
150           new DisplayRealType("displayLine_"+count, true, 0.0, 10000.0, 0.0, null);
151        DisplayRealType displayElemType =
152           new DisplayRealType("displayElem_"+count, true, 0.0, 10000.0, 0.0, null);
153        DisplayRealType displayAltType =
154           new DisplayRealType("displayAlt_"+count, true, -1.0, 1.0, 0.0, null);
155        DisplayTupleType dtt =
156           new DisplayTupleType(new DisplayRealType[] {displayLineType, displayElemType, displayAltType}, new_cs);
157
158
159        RealType elemType = RealType.getRealType("elem_"+count);
160        RealType lineType = RealType.getRealType("line_"+count);
161        this.xType = lineType;
162        this.yType = elemType;
163        this.mask  = mask;
164        bounds = new Gridded2DSet(new RealTupleType(xType, yType), null, 1);
165        //System.out.println("bounds=" + bounds);
166
167        ScalarMap elemMap = new ScalarMap(elemType, displayElemType);
168        ScalarMap lineMap = new ScalarMap(lineType, displayLineType);
169
170        GriddedSet domainSet = (GriddedSet) data.getDomainSet();
171        float[] low = domainSet.getLow();
172        //System.out.println("    low: " + low[0] + " " + low[1]);
173        float[] hi  = domainSet.getHi();
174        //System.out.println("    hi: " + hi[0] + " " + hi[1]);
175
176        elemMap.setRange(low[1], hi[1]);
177        lineMap.setRange(low[0], hi[0]);
178        //System.out.println("elemMap range: " + low[1] + " - " + hi[1]);
179        //System.out.println("lineMap range: " + low[0] + " - " + hi[0]);
180
181        addScalarMap(elemMap);
182        addScalarMap(lineMap);
183
184        //System.out.println("setData bounds=" + bounds);
185        setData(bounds);
186        count += 1;
187    }
188
189    /**
190     * Constructor for creating a RubberBandBox from another instance
191     *
192     * @param that  other instance
193     *
194     * @throws VisADException   VisAD error
195     * @throws RemoteException   Remote error
196     */
197    protected SubsetRubberBandBox(SubsetRubberBandBox that)
198            throws VisADException, RemoteException {
199
200        super(that);
201
202        this.xType  = that.xType;
203        this.yType  = that.yType;
204        this.bounds = that.bounds;
205    }
206
207    /**
208     * Invoked when box mouse is released. Subclasses should invoke
209     * super.dataChange() to ensure the the bounds are set.
210     *
211     * @throws RemoteException
212     * @throws VisADException
213     */
214    protected void dataChange() throws VisADException, RemoteException {
215
216        bounds = (Gridded2DSet) getData();
217            float[] highs = bounds.getHi();
218            float[] lows = bounds.getLow();
219            if (highs != null && lows != null)
220              /*
221                System.out.println("box: X range = " + lows[0] + " to " +
222                                   highs[0] +
223                      "; Y range = " + lows[1] + " to " + highs[1] ); */
224        super.dataChange();
225    }
226
227    /**
228     * Return the bounds of the RubberBandBox.  The Gridded2DSet that
229     * is returned contains the opposite (starting and ending) corners
230     * of the box.
231     *
232     * @return  set containing the opposite corners of the box.
233     */
234    public Gridded2DSet getBounds() {
235        return bounds;
236    }
237
238    /**
239     * Get the DataRenderer used for this displayable.
240     *
241     * @return  RubberBandBoxRendererJ3D associated with this displayable
242     */
243    protected DataRenderer getDataRenderer() {
244        rubberBandBox = new MyRubberBandBoxRendererJ3D(xType, yType, mask,
245                mask);
246        rubberBandBox.setKeepLastBoxOn(lastBoxOn);
247
248        return rubberBandBox;
249    }
250
251    /**
252     * Returns a clone of this instance suitable for another VisAD display.
253     * Underlying data objects are not cloned.
254     *
255     * @return                  A semi-deep clone of this instance.
256     *
257     * @throws VisADException   VisAD failure.
258     * @throws RemoteException  Java RMI failure.
259     */
260    public Displayable cloneForDisplay()
261            throws RemoteException, VisADException {
262        return new SubsetRubberBandBox(this);
263    }
264
265    public void setBox(SubsetRubberBandBox rbb) {
266       rubberBandBox.setLastBox((MyRubberBandBoxRendererJ3D)rbb.getDataRenderer());
267    }
268
269    public Gridded3DSet getLastBox() {
270      return rubberBandBox.last_box;
271    }
272}
273
274
275class DataToDisplayCoordinateSystem extends CoordinateSystem {
276  private CoordinateSystem dataCS;
277  private CoordinateSystem displayCS;
278  private boolean isLL;
279
280
281  DataToDisplayCoordinateSystem(boolean isLL, CoordinateSystem dataCS, CoordinateSystem displayCS) throws VisADException {
282    super(displayCS.getReference(), null);
283    //System.out.println("SubsetRubberBandBox DataToDisplayCoordinateSystem:");
284    //System.out.println("    dataCS=" + dataCS.getClass());
285    //System.out.println("    isLL=" + isLL);
286    //System.out.println("    displayCS=" + displayCS.getClass() + "\n");
287    try {
288        this.dataCS = dataCS;
289        this.displayCS = displayCS;
290        this.isLL = isLL;
291    } catch (Exception e) {
292        System.out.println("e=" + e);
293    }
294  }
295
296  public float[][] toReference(float[][] values) throws VisADException {
297/*
298    System.out.println("\nSubsetRubberBandBox toReference float");
299    System.out.println("    values[0]: " + values[0][0]);
300    System.out.println("    values[1]: " + values[1][0]);
301*/
302    //- if (isLL) values = reverseArrayOrder(values);
303    float[][] new_values = dataCS.toReference(values);
304    if (isLL) new_values = reverseArrayOrder(new_values);
305    new_values = displayCS.toReference(new float[][] {new_values[1], new_values[0], new_values[2]});
306/*
307    System.out.println("    new_values[0]: " + new_values[0][0]);
308    System.out.println("    new_values[1]: " + new_values[1][0]);
309*/
310    return new_values;
311  }
312
313  public float[][] fromReference(float[][] values) throws VisADException {
314/*
315    System.out.println("SubsetRubberBandBox fromReference float");
316    System.out.println("    values[0]: " + values[0][0]);
317    System.out.println("    values[1]: " + values[1][0]);
318*/
319    //- if (isLL) values = reverseArrayOrder(values);
320    float[][] new_values = displayCS.fromReference(values);
321    if (isLL) new_values = reverseArrayOrder(new_values);
322    new_values = dataCS.fromReference(new float[][] {new_values[1], new_values[0], new_values[2]});
323/*
324    System.out.println("    new_values[0]: " + new_values[0][0]);
325    System.out.println("    new_values[1]: " + new_values[1][0]);
326*/
327    return new_values;
328  }
329
330  public double[][] toReference(double[][] values) throws VisADException {
331/*
332    System.out.println("SubsetRubberBandBox toReference double");
333    System.out.println("    values[0]: " + values[0][0]);
334    System.out.println("    values[1]: " + values[1][0]);
335*/
336    //- if (isLL) values = reverseArrayOrder(values);
337    double[][] new_values = dataCS.toReference(values);
338    if (isLL) new_values = reverseArrayOrder(new_values);
339    new_values = displayCS.toReference(new double[][] {new_values[1], new_values[0], new_values[2]});
340/*
341    System.out.println("    new_values[0]: " + new_values[0][0]);
342    System.out.println("    new_values[1]: " + new_values[1][0]);
343*/
344    return new_values;
345  }
346                                                                                                                                  
347  public double[][] fromReference(double[][] values) throws VisADException {
348/*
349    System.out.println("\nSubsetRubberBandBox fromReference double");
350    System.out.println("    values[0]: " + values[0][0]);
351    System.out.println("    values[1]: " + values[1][0]);
352*/
353    //- if (isLL) values = reverseArrayOrder(values);
354    double[][] new_values = displayCS.fromReference(values);
355    if (isLL) new_values = reverseArrayOrder(new_values);
356    new_values = dataCS.fromReference(new double[][] {new_values[1], new_values[0], new_values[2]});
357/*
358    System.out.println("    new_values[0]: " + new_values[0][0]);
359    System.out.println("    new_values[1]: " + new_values[1][0]);
360*/
361    return new_values;
362  }
363
364  public boolean equals(Object obj) {
365    return true;
366  }
367
368    private double[][] reverseArrayOrder(double[][] in) {
369        if (in.length < 2) return in;
370        int len1 = 2;
371        int len2 = in[0].length;
372        double[][] out = new double[in.length][len2];;
373        for (int i=0; i<len1; i++) {
374            for (int j=0; j<len2; j++) {
375                out[len1-i-1][j] = in[i][j];
376            }
377        }
378        if (in.length > 2) {
379            for (int i=2; i<in.length; i++) {
380                for (int j=0; j<len2; j++) {
381                    out[i][j] = in[i][j];
382                }
383            }
384        }
385        return out;
386    }
387
388
389    private float[][] reverseArrayOrder(float[][] in) {
390        if (in.length < 2) return in;
391        int len1 = 2;
392        int len2 = in[0].length;
393        float[][] out = new float[in.length][len2];;
394        for (int i=0; i<len1; i++) {
395            for (int j=0; j<len2; j++) {
396                out[len1-i-1][j] = in[i][j];
397            }
398        }
399        if (in.length > 2) {
400            for (int i=2; i<in.length; i++) {
401                for (int j=0; j<len2; j++) {
402                    out[i][j] = in[i][j];
403                }
404            }
405        }
406        return out;
407    }
408}