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 ucar.visad.display.GridDisplayable;
032    import ucar.visad.display.DisplayableData;
033    import ucar.visad.display.ScalarMapSet;
034    
035    import ucar.unidata.data.grid.GridUtil;
036    
037    import ucar.unidata.util.Misc;
038    
039    import visad.*;
040    
041    import visad.bom.ImageRendererJ3D;
042    import visad.java3d.DefaultRendererJ3D;
043    
044    import visad.java2d.*;
045    import visad.java2d.DefaultRendererJ2D;
046    
047    import visad.java2d.DisplayRendererJ2D;
048    
049    
050    import java.rmi.RemoteException;
051    
052    
053    
054    /**
055     * Provides support for a Displayable that needs a map to
056     * (Display.Red,Display.Green,Display.Blue)
057     *
058     * @author IDV development team
059     * @version $Revision$
060     */
061    public class ImageRGBDisplayable extends DisplayableData implements GridDisplayable {
062    
063    
064        /** color ScalarMaps */
065        private volatile ScalarMap[] colorMaps = { null, null, null };
066    
067        /** color MathType */
068        private volatile RealTupleType colorTupleType;
069    
070        /** color palette */
071        private float[][] colorPalette;
072    
073        /** What do we map with */
074        private DisplayRealType mapType = Display.RGB;
075    
076        /** flag for whether we use Alpha channel or not */
077        private boolean doAlpha = false;
078    
079        private static int uniqueID = 0;
080    
081    
082        /**
083         * Constructs from a name for the Displayable and the type of the
084         * RGB parameter.
085         *
086         * @param name              The name for the displayable.
087         * @throws VisADException   VisAD failure.
088         * @throws RemoteException  Java RMI failure.
089         */
090        public ImageRGBDisplayable(String name)
091                throws VisADException, RemoteException {
092            this(name, false);
093        }
094    
095    
096        /**
097         * Constructs from a name for the Displayable and the type of the
098         * RGB parameter.
099         *
100         * @param name              The name for the displayable.
101         * @param doAlpha           true to map to RGBA
102         * @throws VisADException   VisAD failure.
103         * @throws RemoteException  Java RMI failure.
104         */
105        public ImageRGBDisplayable(String name, boolean doAlpha)
106                throws VisADException, RemoteException {
107            this(name, BaseColorControl.initTableGreyWedge(new float[(doAlpha)
108                    ? 4
109                    : 3][255]), doAlpha);
110        }
111    
112        /**
113         * Constructs from a name for the Displayable and the type of the
114         * RGB parameter.
115         *
116         * @param name              The name for the displayable.
117         * @param colorPalette      The color palette
118         * @param doAlpha           true to map to RGBA
119         * @throws VisADException   VisAD failure.
120         * @throws RemoteException  Java RMI failure.
121         */
122        public ImageRGBDisplayable(String name, float[][] colorPalette,
123                                   boolean doAlpha)
124                throws VisADException, RemoteException {
125            this(name, colorPalette, doAlpha, null);
126        }
127    
128    
129        /**
130         * Constructs from another instance.  The following attributes are set from
131         * the other instance: color palette, the color RealType.
132         * @param that              The other instance.
133         * @throws VisADException   VisAD failure.
134         * @throws RemoteException  Java RMI failure.
135         */
136        protected ImageRGBDisplayable(ImageRGBDisplayable that)
137                throws VisADException, RemoteException {
138    
139            super(that);
140            this.doAlpha   = that.doAlpha;
141            colorTupleType = that.colorTupleType;
142            colorPalette   = Set.copyFloats(that.colorPalette);
143            if (colorTupleType != null) {
144                setColorMaps();
145            }
146        }
147    
148        public ImageRGBDisplayable(String name, float[][] colorPalette, boolean doAlpha, FieldImpl field)
149                throws VisADException, RemoteException {
150            super(name);
151            this.doAlpha = doAlpha;
152            if (doAlpha) {
153                mapType   = Display.RGBA;
154                colorMaps = new ScalarMap[] { null, null, null, null };
155            }
156    
157            addConstantMaps(new ConstantMap[] {
158                new ConstantMap(GraphicsModeControl.SUM_COLOR_MODE,
159                                Display.ColorMode),
160                new ConstantMap(1.0, Display.MissingTransparent) });
161    
162    
163            if (field != null) {
164              TupleType     tt       = GridUtil.getParamType(field);
165              RealTupleType ffldType = new RealTupleType(tt.getRealComponents());
166    
167              if ((getColorTupleType() == null)
168                     || !ffldType.equals(getColorTupleType())) {
169                  setColorTupleType(ffldType);
170              }
171            }
172        }
173          
174    
175    
176        /**
177         * Set the data into the Displayable; set RGB Type
178         *
179         *
180         * @param field an image or sequence of images
181         * @exception VisADException  from construction of VisAd objects
182         * @exception RemoteException from construction of VisAD objects
183         */
184        public void loadData(FieldImpl field)
185                throws VisADException, RemoteException {
186            setData(field);
187        }
188    
189    
190        /**
191         * Get the RealTupleType of the RGB parameter.
192         *  @return The RealTupleType of the RGB parameters.
193         *         May be <code>null</code>.
194         */
195        public RealTupleType getColorTupleType() {
196            return colorTupleType;
197        }
198    
199        /**
200         * Sets the RealTupleType of the RGB parameter.
201         * @param realTupleType     The RealTupleType of the RGB parameters.  May
202         *                          not be <code>null</code>.
203         * @throws VisADException   VisAD failure.
204         * @throws RemoteException  Java RMI failure.
205         */
206        protected void setColorTupleType(RealTupleType realTupleType)
207                throws RemoteException, VisADException {
208    
209            if ( !realTupleType.equals(colorTupleType)) {
210                RealTupleType oldValue = colorTupleType;
211                colorTupleType = realTupleType;
212                setColorMaps();
213            }
214        }
215    
216    
217        /**
218         * Returns the RealTupleType of the RGB parameter.
219         * @return                  The RealTupleType of the color parameter.  May
220         *                          be <code>null</code>.
221         * @deprecated  use getColorTupleType()
222         */
223        public RealTupleType getRGBRealTupleType() {
224            return colorTupleType;
225        }
226    
227    
228        /**
229         * Sets the set of ScalarMap-s of this instance.  The ScalarMap-s of
230         * this instance will be added to the set before the SCALAR_MAP_SET
231         * property is set.  This method fires a PropertyChangeEvent for
232         * SCALAR_MAP_SET with <code>null</code> for the old value and the new
233         * set of ScalarMap-s for the new Value.  Intermediate subclasses that
234         * have their own ScalarMap-s should override this method and invoke
235         * <code>super.setScalarMaps(ScalarMapSet)</code>.
236         * @param maps              The set of ScalarMap-s to be added.
237         * @throws BadMappingException      The RealType of the color parameter
238         *                          has not been set or its ScalarMap is alread in
239         *                          the set.
240         */
241        protected void setScalarMaps(ScalarMapSet maps)
242                throws BadMappingException {
243    
244            if (colorMaps[0] == null) {
245                throw new BadMappingException(getClass().getName()
246                                              + ".setScalarMaps(ScalarMapSet): "
247                                              + "Color not yet set");
248            }
249    
250            for (int i = 0; i < colorMaps.length; i++) {
251                maps.add(colorMaps[i]);
252            }
253            super.setScalarMapSet(maps);
254        }
255    
256        /**
257         * Set the alpha. Unused.
258         *
259         * @param alpha alpha
260         *
261         * @throws RemoteException On badness
262         * @throws VisADException On badness
263         */
264        public void setAlpha(float alpha) throws RemoteException, VisADException {
265            addConstantMaps(new ConstantMap[] {
266                new ConstantMap(alpha, Display.Alpha) });
267        }
268    
269        /**
270         * creates the ScalarMaps for color  for this Displayable.
271         *
272         * @throws VisADException   VisAD failure.
273         * @throws RemoteException  Java RMI failure.
274         */
275        private void setColorMaps() throws RemoteException, VisADException {
276    
277            ScalarMapSet set = new ScalarMapSet();
278            for (int i = 0; i < colorMaps.length; i++) {
279                colorMaps[i] =
280                    new ScalarMap((RealType) colorTupleType.getComponent(i),
281                                  mapType);
282                /* TODO: maybe allow user to set range.  If so, just copy
283                   logic from RGBDisplayable */
284                //-TDR colorMaps[i].setRange(0, 255);
285                set.add(colorMaps[i]);
286                final int colorMapIndex = i;
287                colorMaps[i].addScalarMapListener(new ScalarMapListener() {
288                    public void controlChanged(ScalarMapControlEvent event)
289                            throws RemoteException, VisADException {
290                        int id = event.getId();
291                        if ((id == event.CONTROL_ADDED)
292                                || (id == event.CONTROL_REPLACED)) {
293                            setColorsInControls(colorPalette, colorMapIndex);
294                        }
295                    }
296    
297                    public void mapChanged(ScalarMapEvent event)
298                            throws RemoteException, VisADException { 
299                    }
300                });
301            }
302    
303            setScalarMapSet(set);
304            setColorsInControls(colorPalette);
305        }
306    
307        /**
308         * Set the display.
309         *
310         * @param display  display to set this into
311         *
312         * @throws DisplayException Display type exception
313         * @throws RemoteException  Java RMI error
314         * @throws VisADException   problem creating VisAD object
315         */
316        public void setDisplay(LocalDisplay display)
317                throws DisplayException, VisADException, RemoteException {
318            super.setDisplay(display);
319            setColorsInControls(colorPalette);
320        }
321    
322        /**
323         * This method sets the color palette
324         * according to the color table in argument;
325         * pair this method with setRange(lo,high) to get
326         * a fixed association of color table and range of values.
327         *
328         * @param colorPalette     the color table or color-alpha table desired
329         * @throws VisADException  if a core VisAD failure occurs.
330         * @throws RemoteException if a Java RMI failure occurs.
331         */
332        public void setColorPalette(float[][] colorPalette)
333                throws RemoteException, VisADException {
334    
335            setColorsInControls(colorPalette);
336            this.colorPalette = colorPalette;
337        }
338    
339        /**
340         * Return the current color palette in this Displayable
341         *
342         * @return a color table float[3][len] or color-alpha table float[4][len]
343         */
344        public float[][] getColorPalette() {
345            return colorPalette;
346        }
347    
348    
349        /**
350         * Set colors for the controls of all color maps.
351         *
352         * @param colorPalette The 3xN color palette array
353         *
354         * @throws RemoteException  Java RMI error
355         * @throws VisADException   problem creating VisAD object
356         */
357        private void setColorsInControls(float[][] colorPalette)
358                throws RemoteException, VisADException {
359    
360            for (int i = 0; i < colorMaps.length; i++) {
361                setColorsInControls(colorPalette, i);
362            }
363        }
364    
365    
366    
367    
368        /**
369         * Set colors for the control defined by the given colorMapIndex (0,1 or 2).
370         *
371         * @param colorPalette The 3xN color palette array
372         * @param colorMapIndex Which of the color maps are we setting the color of.
373         *
374         * @throws RemoteException  Java RMI error
375         * @throws VisADException   problem creating VisAD object
376         */
377        private void setColorsInControls(float[][] colorPalette,
378                                         int colorMapIndex)
379                throws RemoteException, VisADException {
380            if (colorPalette == null) {
381                return;
382            }
383    
384    
385            if (colorMaps[colorMapIndex] == null) {
386                return;
387            }
388    
389            BaseColorControl bcc =
390                (BaseColorControl) colorMaps[colorMapIndex].getControl();
391    
392            if (bcc != null) {
393                float[][] table =
394                    new float[colorMaps.length][colorPalette[0].length];
395                table[colorMapIndex] = colorPalette[colorMapIndex];
396                bcc.setTable(table);
397            }
398        }
399    
400        protected DataRenderer getDataRenderer() throws VisADException {
401         
402          ImageRendererJ3D myRenderer = new ImageRendererJ3D();
403          return myRenderer;
404    
405        }
406    
407    
408        /**
409         * Set whether this GridDisplayable should have the data colored
410         * by another parameter.  This implementation is a no-op.
411         *
412         * @param yesno true if colored by another
413         */
414        public void setColoredByAnother(boolean yesno) {}
415    
416    }