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