001/*
002 * $Id: ImageRGBDisplayable.java,v 1.6 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 ucar.visad.display.GridDisplayable;
034import ucar.visad.display.DisplayableData;
035import ucar.visad.display.ScalarMapSet;
036
037import ucar.unidata.data.grid.GridUtil;
038
039import ucar.unidata.util.Misc;
040
041import visad.*;
042
043import visad.bom.ImageRendererJ3D;
044import visad.java3d.DefaultRendererJ3D;
045
046import visad.java2d.*;
047import visad.java2d.DefaultRendererJ2D;
048
049import visad.java2d.DisplayRendererJ2D;
050
051
052import 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.6 $
062 */
063public 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}