001    /*
002     * $Id: SubsetRubberBandBox.java,v 1.13 2012/03/27 21:58:01 rink Exp $
003     *
004     * This file is part of McIDAS-V
005     *
006     * Copyright 2007-2012
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    package edu.wisc.ssec.mcidasv.data.hydra;
032    
033    import edu.wisc.ssec.mcidasv.data.hydra.MyRubberBandBoxRendererJ3D;
034    
035    import ucar.visad.display.Displayable;
036    import ucar.visad.display.LineDrawing;
037    
038    import visad.*;
039    import visad.bom.*;
040    
041    import java.rmi.RemoteException;
042    
043    import java.awt.event.InputEvent;
044    
045    
046    public 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            RealTupleType rtype = ((FunctionType)data.getType()).getDomain();
126            dataCS = rtype.getCoordinateSystem();
127            if (dataCS == null) {
128              dataCS = new GridCoordinateSystem((GriddedSet)data.getDomainSet());
129            }
130    
131            IdentityCoordinateSystem iCS =
132                 new IdentityCoordinateSystem(
133                       new RealTupleType(new RealType[] {RealType.getRealType("ZZtop")}));
134    
135            CoordinateSystem cs =
136                 new CartesianProductCoordinateSystem(new CoordinateSystem[] {dataCS, iCS});
137    
138            CoordinateSystem new_cs = new DataToDisplayCoordinateSystem(isLL, cs, displayCS);
139            
140    
141            DisplayRealType displayLineType =
142               new DisplayRealType("displayLine_"+count, true, 0.0, 10000.0, 0.0, null);
143            DisplayRealType displayElemType =
144               new DisplayRealType("displayElem_"+count, true, 0.0, 10000.0, 0.0, null);
145            DisplayRealType displayAltType =
146               new DisplayRealType("displayAlt_"+count, true, -1.0, 1.0, 0.0, null);
147            DisplayTupleType dtt =
148               new DisplayTupleType(new DisplayRealType[] {displayLineType, displayElemType, displayAltType}, new_cs);
149    
150    
151            RealType elemType = RealType.getRealType("elem_"+count);
152            RealType lineType = RealType.getRealType("line_"+count);
153            this.xType = lineType;
154            this.yType = elemType;
155            this.mask  = mask;
156            bounds = new Gridded2DSet(new RealTupleType(xType, yType), null, 1);
157    
158            ScalarMap elemMap = new ScalarMap(elemType, displayElemType);
159            ScalarMap lineMap = new ScalarMap(lineType, displayLineType);
160    
161            GriddedSet domainSet = (GriddedSet) data.getDomainSet();
162            float[] low = domainSet.getLow();
163            float[] hi  = domainSet.getHi();
164    
165            elemMap.setRange(low[1], hi[1]);
166            lineMap.setRange(low[0], hi[0]);
167    
168            addScalarMap(elemMap);
169            addScalarMap(lineMap);
170    
171            setData(bounds);
172            count += 1;
173        }
174    
175        /**
176         * Constructor for creating a RubberBandBox from another instance
177         *
178         * @param that  other instance
179         *
180         * @throws VisADException   VisAD error
181         * @throws RemoteException   Remote error
182         */
183        protected SubsetRubberBandBox(SubsetRubberBandBox that)
184                throws VisADException, RemoteException {
185    
186            super(that);
187    
188            this.xType  = that.xType;
189            this.yType  = that.yType;
190            this.bounds = that.bounds;
191        }
192    
193        /**
194         * Invoked when box mouse is released. Subclasses should invoke
195         * super.dataChange() to ensure the the bounds are set.
196         *
197         * @throws RemoteException
198         * @throws VisADException
199         */
200        protected void dataChange() throws VisADException, RemoteException {
201    
202            bounds = (Gridded2DSet) getData();
203                float[] highs = bounds.getHi();
204                float[] lows = bounds.getLow();
205                if (highs != null && lows != null)
206            super.dataChange();
207        }
208    
209        /**
210         * Return the bounds of the RubberBandBox.  The Gridded2DSet that
211         * is returned contains the opposite (starting and ending) corners
212         * of the box.
213         *
214         * @return  set containing the opposite corners of the box.
215         */
216        public Gridded2DSet getBounds() {
217            return bounds;
218        }
219    
220        /**
221         * Get the DataRenderer used for this displayable.
222         *
223         * @return  RubberBandBoxRendererJ3D associated with this displayable
224         */
225        protected DataRenderer getDataRenderer() {
226            rubberBandBox = new MyRubberBandBoxRendererJ3D(xType, yType, mask,
227                    mask);
228            rubberBandBox.setKeepLastBoxOn(lastBoxOn);
229    
230            return rubberBandBox;
231        }
232    
233        /**
234         * Returns a clone of this instance suitable for another VisAD display.
235         * Underlying data objects are not cloned.
236         *
237         * @return                  A semi-deep clone of this instance.
238         *
239         * @throws VisADException   VisAD failure.
240         * @throws RemoteException  Java RMI failure.
241         */
242        public Displayable cloneForDisplay()
243                throws RemoteException, VisADException {
244            return new SubsetRubberBandBox(this);
245        }
246    
247        public void setBox(SubsetRubberBandBox rbb) {
248           rubberBandBox.setLastBox((MyRubberBandBoxRendererJ3D)rbb.getDataRenderer());
249        }
250    
251        public Gridded3DSet getLastBox() {
252          return rubberBandBox.last_box;
253        }
254    }
255    
256    
257    class DataToDisplayCoordinateSystem extends CoordinateSystem {
258      private CoordinateSystem dataCS;
259      private CoordinateSystem displayCS;
260      private boolean isLL;
261    
262    
263      DataToDisplayCoordinateSystem(boolean isLL, CoordinateSystem dataCS, CoordinateSystem displayCS) throws VisADException {
264        super(displayCS.getReference(), null);
265        try {
266            this.dataCS = dataCS;
267            this.displayCS = displayCS;
268            this.isLL = isLL;
269        } catch (Exception e) {
270            System.out.println("e=" + e);
271        }
272      }
273    
274      public float[][] toReference(float[][] values) throws VisADException {
275        //- if (isLL) values = reverseArrayOrder(values);
276        float[][] new_values = dataCS.toReference(values);
277        if (isLL) new_values = reverseArrayOrder(new_values);
278        new_values = displayCS.toReference(new float[][] {new_values[1], new_values[0], new_values[2]});
279        return new_values;
280      }
281    
282      public float[][] fromReference(float[][] values) throws VisADException {
283        //- if (isLL) values = reverseArrayOrder(values);
284        float[][] new_values = displayCS.fromReference(values);
285        if (isLL) new_values = reverseArrayOrder(new_values);
286        new_values = dataCS.fromReference(new float[][] {new_values[1], new_values[0], new_values[2]});
287    
288        return new_values;
289      }
290    
291      public double[][] toReference(double[][] values) throws VisADException {
292        //- if (isLL) values = reverseArrayOrder(values);
293        double[][] new_values = dataCS.toReference(values);
294        if (isLL) new_values = reverseArrayOrder(new_values);
295        new_values = displayCS.toReference(new double[][] {new_values[1], new_values[0], new_values[2]});
296    
297        return new_values;
298      }
299                                                                                                                                      
300      public double[][] fromReference(double[][] values) throws VisADException {
301        //- if (isLL) values = reverseArrayOrder(values);
302        double[][] new_values = displayCS.fromReference(values);
303        if (isLL) new_values = reverseArrayOrder(new_values);
304        new_values = dataCS.fromReference(new double[][] {new_values[1], new_values[0], new_values[2]});
305        return new_values;
306      }
307    
308      public boolean equals(Object obj) {
309        return true;
310      }
311    
312        private double[][] reverseArrayOrder(double[][] in) {
313            if (in.length < 2) return in;
314            int len1 = 2;
315            int len2 = in[0].length;
316            double[][] out = new double[in.length][len2];;
317            for (int i=0; i<len1; i++) {
318                for (int j=0; j<len2; j++) {
319                    out[len1-i-1][j] = in[i][j];
320                }
321            }
322            if (in.length > 2) {
323                for (int i=2; i<in.length; i++) {
324                    for (int j=0; j<len2; j++) {
325                        out[i][j] = in[i][j];
326                    }
327                }
328            }
329            return out;
330        }
331    
332    
333        private float[][] reverseArrayOrder(float[][] in) {
334            if (in.length < 2) return in;
335            int len1 = 2;
336            int len2 = in[0].length;
337            float[][] out = new float[in.length][len2];;
338            for (int i=0; i<len1; i++) {
339                for (int j=0; j<len2; j++) {
340                    out[len1-i-1][j] = in[i][j];
341                }
342            }
343            if (in.length > 2) {
344                for (int i=2; i<in.length; i++) {
345                    for (int j=0; j<len2; j++) {
346                        out[i][j] = in[i][j];
347                    }
348                }
349            }
350            return out;
351        }
352    }