001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
005     * Space Science and Engineering Center (SSEC)
006     * University of Wisconsin - Madison
007     * 1225 W. Dayton Street, Madison, WI 53706, USA
008     * https://www.ssec.wisc.edu/mcidas
009     * 
010     * All Rights Reserved
011     * 
012     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013     * some McIDAS-V source code is based on IDV and VisAD source code.  
014     * 
015     * McIDAS-V is free software; you can redistribute it and/or modify
016     * it under the terms of the GNU Lesser Public License as published by
017     * the Free Software Foundation; either version 3 of the License, or
018     * (at your option) any later version.
019     * 
020     * McIDAS-V is distributed in the hope that it will be useful,
021     * but WITHOUT ANY WARRANTY; without even the implied warranty of
022     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     * GNU Lesser Public License for more details.
024     * 
025     * You should have received a copy of the GNU Lesser Public License
026     * along with this program.  If not, see http://www.gnu.org/licenses.
027     */
028    
029    package edu.wisc.ssec.mcidasv.data.hydra;
030    
031    import edu.wisc.ssec.mcidasv.data.hydra.MyRubberBandBoxRendererJ3D;
032    
033    import ucar.visad.display.Displayable;
034    import ucar.visad.display.LineDrawing;
035    
036    import visad.*;
037    import visad.bom.*;
038    
039    import java.rmi.RemoteException;
040    
041    import java.awt.event.InputEvent;
042    
043    
044    public class SubsetRubberBandBox extends LineDrawing {
045    
046        /** x type for the box */
047        private RealType xType;
048    
049        /** y type for the box */
050        private RealType yType;
051    
052        /** renderer */
053        private MyRubberBandBoxRendererJ3D rubberBandBox;
054    
055        /** bounds defined by the rubber band box */
056        private Gridded2DSet bounds;
057    
058        /** mouse event mask */
059        private int mask;
060    
061        private FlatField data;
062        private boolean isLL;
063        private boolean lastBoxOn;
064    
065        private CoordinateSystem dataCS;
066    
067        private CoordinateSystem displayCS;
068    
069        private static int count = 0;
070    
071        /**
072         * Construct a RubberBandBox using xType as the X coordinate and
073         * yType as the Y coordinate of the box.
074         *
075         * @param  xType   RealType of the X coordinate of the box
076         * @param  yType   RealType of the Y coordinate of the box
077         *
078         * @throws VisADException   VisAD error
079         * @throws RemoteException   Remote error
080         */
081        public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS)
082                throws VisADException, RemoteException {
083            this(false, data, displayCS, 0);
084        }
085    
086        public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask)
087                throws VisADException, RemoteException {
088            this(false, data, displayCS, mask);
089        }
090    
091        public SubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask)
092                throws VisADException, RemoteException {
093            this(isLL, data, displayCS, mask, true);
094        }
095    
096        public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn)
097                throws VisADException, RemoteException {
098            this(false, data, displayCS, mask, lastBoxOn);
099        }
100    
101    
102    
103        /**
104         * Construct a RubberBandBox using xType as the X coordinate and
105         * yType as the Y coordinate of the box.
106         *
107         * @param xType   RealType of the X coordinate of the box
108         * @param yType   RealType of the Y coordinate of the box
109         * @param mask    key mask to use for rubberbanding
110         *
111         * @throws VisADException   VisAD error
112         * @throws RemoteException   Remote error
113         */
114        public SubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn)
115                throws VisADException, RemoteException {
116            super("Subset Rubber Band Box");
117    
118            this.data = data;
119            this.displayCS = displayCS;
120            this.isLL = isLL;
121            this.lastBoxOn =  lastBoxOn;
122    
123            RealTupleType rtype = ((FunctionType)data.getType()).getDomain();
124            dataCS = rtype.getCoordinateSystem();
125            if (dataCS == null) {
126              dataCS = new GridCoordinateSystem((GriddedSet)data.getDomainSet());
127            }
128    
129            IdentityCoordinateSystem iCS =
130                 new IdentityCoordinateSystem(
131                       new RealTupleType(new RealType[] {RealType.getRealType("ZZtop")}));
132    
133            CoordinateSystem cs =
134                 new CartesianProductCoordinateSystem(new CoordinateSystem[] {dataCS, iCS});
135    
136            CoordinateSystem new_cs = new DataToDisplayCoordinateSystem(isLL, cs, displayCS);
137            
138    
139            DisplayRealType displayLineType =
140               new DisplayRealType("displayLine_"+count, true, 0.0, 10000.0, 0.0, null);
141            DisplayRealType displayElemType =
142               new DisplayRealType("displayElem_"+count, true, 0.0, 10000.0, 0.0, null);
143            DisplayRealType displayAltType =
144               new DisplayRealType("displayAlt_"+count, true, -1.0, 1.0, 0.0, null);
145            DisplayTupleType dtt =
146               new DisplayTupleType(new DisplayRealType[] {displayLineType, displayElemType, displayAltType}, new_cs);
147    
148    
149            RealType elemType = RealType.getRealType("elem_"+count);
150            RealType lineType = RealType.getRealType("line_"+count);
151            this.xType = lineType;
152            this.yType = elemType;
153            this.mask  = mask;
154            bounds = new Gridded2DSet(new RealTupleType(xType, yType), null, 1);
155    
156            ScalarMap elemMap = new ScalarMap(elemType, displayElemType);
157            ScalarMap lineMap = new ScalarMap(lineType, displayLineType);
158    
159            GriddedSet domainSet = (GriddedSet) data.getDomainSet();
160            float[] low = domainSet.getLow();
161            float[] hi  = domainSet.getHi();
162    
163            elemMap.setRange(low[1], hi[1]);
164            lineMap.setRange(low[0], hi[0]);
165    
166            addScalarMap(elemMap);
167            addScalarMap(lineMap);
168    
169            setData(bounds);
170            count += 1;
171        }
172    
173        /**
174         * Constructor for creating a RubberBandBox from another instance
175         *
176         * @param that  other instance
177         *
178         * @throws VisADException   VisAD error
179         * @throws RemoteException   Remote error
180         */
181        protected SubsetRubberBandBox(SubsetRubberBandBox that)
182                throws VisADException, RemoteException {
183    
184            super(that);
185    
186            this.xType  = that.xType;
187            this.yType  = that.yType;
188            this.bounds = that.bounds;
189        }
190    
191        /**
192         * Invoked when box mouse is released. Subclasses should invoke
193         * super.dataChange() to ensure the the bounds are set.
194         *
195         * @throws RemoteException
196         * @throws VisADException
197         */
198        protected void dataChange() throws VisADException, RemoteException {
199    
200            bounds = (Gridded2DSet) getData();
201                float[] highs = bounds.getHi();
202                float[] lows = bounds.getLow();
203                if (highs != null && lows != null)
204            super.dataChange();
205        }
206    
207        /**
208         * Return the bounds of the RubberBandBox.  The Gridded2DSet that
209         * is returned contains the opposite (starting and ending) corners
210         * of the box.
211         *
212         * @return  set containing the opposite corners of the box.
213         */
214        public Gridded2DSet getBounds() {
215            return bounds;
216        }
217    
218        /**
219         * Get the DataRenderer used for this displayable.
220         *
221         * @return  RubberBandBoxRendererJ3D associated with this displayable
222         */
223        protected DataRenderer getDataRenderer() {
224            rubberBandBox = new MyRubberBandBoxRendererJ3D(xType, yType, mask,
225                    mask);
226            rubberBandBox.setKeepLastBoxOn(lastBoxOn);
227    
228            return rubberBandBox;
229        }
230    
231        /**
232         * Returns a clone of this instance suitable for another VisAD display.
233         * Underlying data objects are not cloned.
234         *
235         * @return                  A semi-deep clone of this instance.
236         *
237         * @throws VisADException   VisAD failure.
238         * @throws RemoteException  Java RMI failure.
239         */
240        public Displayable cloneForDisplay()
241                throws RemoteException, VisADException {
242            return new SubsetRubberBandBox(this);
243        }
244    
245        public void setBox(SubsetRubberBandBox rbb) {
246           rubberBandBox.setLastBox((MyRubberBandBoxRendererJ3D)rbb.getDataRenderer());
247        }
248    
249        public Gridded3DSet getLastBox() {
250          return rubberBandBox.last_box;
251        }
252    }
253    
254    
255    class DataToDisplayCoordinateSystem extends CoordinateSystem {
256      private CoordinateSystem dataCS;
257      private CoordinateSystem displayCS;
258      private boolean isLL;
259    
260    
261      DataToDisplayCoordinateSystem(boolean isLL, CoordinateSystem dataCS, CoordinateSystem displayCS) throws VisADException {
262        super(displayCS.getReference(), null);
263        try {
264            this.dataCS = dataCS;
265            this.displayCS = displayCS;
266            this.isLL = isLL;
267        } catch (Exception e) {
268            System.out.println("e=" + e);
269        }
270      }
271    
272      public float[][] toReference(float[][] values) throws VisADException {
273        //- if (isLL) values = reverseArrayOrder(values);
274        float[][] new_values = dataCS.toReference(values);
275        if (isLL) new_values = reverseArrayOrder(new_values);
276        new_values = displayCS.toReference(new float[][] {new_values[1], new_values[0], new_values[2]});
277        return new_values;
278      }
279    
280      public float[][] fromReference(float[][] values) throws VisADException {
281        //- if (isLL) values = reverseArrayOrder(values);
282        float[][] new_values = displayCS.fromReference(values);
283        if (isLL) new_values = reverseArrayOrder(new_values);
284        new_values = dataCS.fromReference(new float[][] {new_values[1], new_values[0], new_values[2]});
285    
286        return new_values;
287      }
288    
289      public double[][] toReference(double[][] values) throws VisADException {
290        //- if (isLL) values = reverseArrayOrder(values);
291        double[][] new_values = dataCS.toReference(values);
292        if (isLL) new_values = reverseArrayOrder(new_values);
293        new_values = displayCS.toReference(new double[][] {new_values[1], new_values[0], new_values[2]});
294    
295        return new_values;
296      }
297                                                                                                                                      
298      public double[][] fromReference(double[][] values) throws VisADException {
299        //- if (isLL) values = reverseArrayOrder(values);
300        double[][] new_values = displayCS.fromReference(values);
301        if (isLL) new_values = reverseArrayOrder(new_values);
302        new_values = dataCS.fromReference(new double[][] {new_values[1], new_values[0], new_values[2]});
303        return new_values;
304      }
305    
306      public boolean equals(Object obj) {
307        return true;
308      }
309    
310        private double[][] reverseArrayOrder(double[][] in) {
311            if (in.length < 2) return in;
312            int len1 = 2;
313            int len2 = in[0].length;
314            double[][] out = new double[in.length][len2];;
315            for (int i=0; i<len1; i++) {
316                for (int j=0; j<len2; j++) {
317                    out[len1-i-1][j] = in[i][j];
318                }
319            }
320            if (in.length > 2) {
321                for (int i=2; i<in.length; i++) {
322                    for (int j=0; j<len2; j++) {
323                        out[i][j] = in[i][j];
324                    }
325                }
326            }
327            return out;
328        }
329    
330    
331        private float[][] reverseArrayOrder(float[][] in) {
332            if (in.length < 2) return in;
333            int len1 = 2;
334            int len2 = in[0].length;
335            float[][] out = new float[in.length][len2];;
336            for (int i=0; i<len1; i++) {
337                for (int j=0; j<len2; j++) {
338                    out[len1-i-1][j] = in[i][j];
339                }
340            }
341            if (in.length > 2) {
342                for (int i=2; i<in.length; i++) {
343                    for (int j=0; j<len2; j++) {
344                        out[i][j] = in[i][j];
345                    }
346                }
347            }
348            return out;
349        }
350    }