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 java.rmi.RemoteException;
032    
033    import java.util.Iterator;
034    
035    import java.awt.Color;
036    
037    import ucar.unidata.beans.*;
038    
039    import visad.*;
040    
041    import ucar.visad.display.DisplayMaster;
042    import ucar.visad.display.Displayable;
043    import ucar.visad.display.DisplayableData;
044    import ucar.visad.display.ScalarMapSet;
045    import ucar.unidata.util.Range;
046                                                                                                                                          
047    import visad.RealType;
048    import visad.ScalarMap;
049    import visad.BadMappingException;
050    import visad.LocalDisplay;
051    import visad.DataReference;
052    import visad.VisADException;
053    import visad.UnimplementedException;
054    import visad.bom.ImageRendererJ3D;
055    import visad.java3d.DefaultRendererJ3D;
056    import java.rmi.RemoteException;
057                                                                                                                                          
058    import java.util.ArrayList;
059    import java.util.Hashtable;
060    import java.util.List;
061    import java.util.Iterator;
062    
063    import edu.wisc.ssec.mcidasv.control.HydraControl;
064    import edu.wisc.ssec.mcidasv.control.MultiSpectralControl;
065    
066    
067    public class HydraRGBDisplayable extends DisplayableData {
068    
069        /**
070         * The name of the "color palette" property.
071         */
072        public static final String COLOR_PALETTE = "colorPalette";
073    
074        /**
075         * The name of the "RGB real-type" property.
076         */
077        public static final String RGB_REAL_TYPE = "rgbRealType";
078    
079        /**
080         * The polygon fill style
081         */
082        public static final int POLYGON_FILL = 0;
083    
084        /**
085         * The polygon line style
086         */
087        public static final int POLYGON_LINE = 1;
088    
089        /**
090         * The polygon point style
091         */
092        public static final int POLYGON_POINT = 2;
093    
094        /**
095         * Color Palette
096         */
097        private float[][] colorPalette = null;
098    
099        private String colorPaletteName = null;
100    
101        /** color ScalarMap */
102        private volatile ScalarMap colorMap;
103    
104        /** field index to Animation ScalarMap */
105        private volatile ScalarMap animMap;
106    
107        /** control for ScalarMap */
108        private volatile BaseColorControl colorControl;
109    
110        /** RealType for the ScalarMap */
111        private volatile RealType rgbRealType;
112    
113        /** RealType for the SelectRange ScalarMap */
114        private ScalarMap selectMap = null;
115    
116        /** RealType for the Animation ScalarMap */
117        private RealType indexRealType;
118    
119        /** Control for select range */
120        private RangeControl selectControl;
121    
122        /** RealType for the SelectRange ScalarMap */
123        private RealType selectRealType = null;
124    
125        /** flag for whether alpha is used or not */
126        private boolean alphaflag;
127    
128        /** local point size */
129        private float myPointSize;
130    
131        /** low range for colors */
132        //private double lowRange = 315;           // low range for scalarmap
133        private double lowRange = Double.NaN;           // low range for scalarmap
134    
135        /** high range for colors */
136        //private double highRange = 230;          // high range for scalarmap
137        private double highRange = Double.NaN;          // high range for scalarmap
138    
139        /** default polygonMode */
140        private int polygonMode = POLYGON_FILL;
141    
142        /** default curvedSize */
143        private int curvedSize = 10;
144    
145        /** low range for select */
146        private double lowSelectedRange = Double.NaN;   // low range for scalarmap
147    
148        /** high range for select */
149        private double highSelectedRange = Double.NaN;  // high range for scalarmap
150    
151        /** low range for select map */
152        private double minSelect = Double.NaN;          // low range for scalarmap
153    
154        /** high range for select map */
155        private double maxSelect = Double.NaN;          // high range for scalarmap
156    
157        private HydraControl multiSpecCntrl;
158    
159        private boolean useDefaultRenderer = false;
160    
161        /**
162         * Constructs from a name for the Displayable and the type of the
163         * RGB parameter.
164         *
165         * @param name              The name for the displayable.
166         * @param rgbRealType       The type of the RGB parameter.  May be
167         *                          <code>null</code>.
168         * @param alphaflag         boolean - will use Display.RBGA if true
169         *                            otherwise only Display.RGB
170         * @throws VisADException   VisAD failure.
171         * @throws RemoteException  Java RMI failure.
172         */
173        public HydraRGBDisplayable(String name, RealType rgbRealType, RealType indexRealType, boolean alphaflag, 
174                     HydraControl multiSpecCntrl)
175                throws VisADException, RemoteException {
176            this(name, rgbRealType, indexRealType, null, alphaflag, null, multiSpecCntrl);
177        }
178    
179        public HydraRGBDisplayable(String name, RealType rgbRealType, RealType indexRealType, float[][] colorPalette, boolean alphaflag, Range initRange,
180                       HydraControl multiSpecCntrl)
181                throws VisADException, RemoteException {
182            this(name, rgbRealType, indexRealType, colorPalette, null, alphaflag, initRange, multiSpecCntrl);
183        }
184    
185        /**
186         * Constructs from a name for the Displayable and the type of the
187         * RGB parameter.
188         *
189         * @param name              The name for the displayable.
190         * @param rgbRealType       The type of the RGB parameter.  May be
191         *                          <code>null</code>.
192         * @param colorPalette      The initial colorPalette to use. May be
193         *                          <code>null</code> (Vis5D palette used
194         *                          as default).
195         * @param alphaflag         boolean - use Display.RBGA if true
196         * @param initRange         Range to use as initial or first min,max
197         * @throws VisADException   VisAD failure.
198         * @throws RemoteException  Java RMI failure.
199         */
200        public HydraRGBDisplayable(String name, RealType rgbRealType, RealType indexRealType, float[][] colorPalette, String colorPaletteName, boolean alphaflag, Range initRange,
201                       HydraControl multiSpecCntrl)
202                throws VisADException, RemoteException {
203    
204            super(name);
205            
206            this.rgbRealType  = rgbRealType;
207            this.selectRealType = rgbRealType;
208            this.indexRealType  = indexRealType;
209            this.colorPalette = colorPalette;
210            this.colorPaletteName = colorPaletteName;
211            this.alphaflag    = alphaflag;
212            this.multiSpecCntrl = multiSpecCntrl;
213    
214            if (initRange != null) {
215              this.lowRange = initRange.getMin();
216              this.highRange = initRange.getMax();
217            }
218    
219            if (rgbRealType != null) {
220                setColorMaps();
221                if (useDisplayUnitForColor()) {
222                    setDisplayUnit(rgbRealType.getDefaultUnit());
223                } else {
224                    setColorUnit(rgbRealType.getDefaultUnit());
225                }
226            }
227    
228            if (indexRealType != null) {
229              //-setAnimationMap();
230              setSelectMap();
231            }
232    
233            if (selectRealType != null) {
234              //setSelectMaps();
235            }
236        }
237    
238        /**
239         * Does this object use the displayUnit (or the colorUnit) for its
240         * display unit. The default is true.  This allows derived classes
241         * to have this class use the colorUnit.
242         * @return  true if the display unit is the same as the color unit
243         */
244        protected boolean useDisplayUnitForColor() {
245            return true;
246        }
247    
248    
249        /**
250         * Constructs from another instance.  The following attributes are set from
251         * the other instance: color palette, the color RealType.
252         * @param that              The other instance.
253         * @throws VisADException   VisAD failure.
254         * @throws RemoteException  Java RMI failure.
255         */
256        protected HydraRGBDisplayable(HydraRGBDisplayable that)
257                throws VisADException, RemoteException {
258    
259            super(that);
260            colorPalette = that.colorPalette;
261            rgbRealType  = that.rgbRealType;  // immutable object
262            alphaflag    = that.alphaflag;
263    
264            if (rgbRealType != null) {
265                setColorMaps();
266            }
267        }
268    
269        /**
270         * Sets the RealType of the RGB parameter.
271         * @param realType          The RealType of the RGB parameter.  May
272         *                          not be <code>null</code>.
273         * @throws VisADException   VisAD failure.
274         * @throws RemoteException  Java RMI failure.
275         */
276        public void setRGBRealType(RealType realType)
277                throws RemoteException, VisADException {
278    
279            if ( !realType.equals(rgbRealType)) {
280                RealType oldValue = rgbRealType;
281                rgbRealType = realType;
282                setColorMaps();
283                if (useDisplayUnitForColor()) {
284                    if ( !isUnitCompatible(rgbRealType, getDisplayUnit())) {
285                        setDisplayUnit(null);
286                    }
287                } else {
288                    if ( !isUnitCompatible(rgbRealType, getColorUnit())) {
289                        setColorUnit(null);
290                    }
291                }
292                firePropertyChange(RGB_REAL_TYPE, oldValue, rgbRealType);
293            }
294        }
295    
296        public ScalarMap getColorMap() {
297          return colorMap;
298        }
299    
300        public ScalarMap getAnimationMap() {
301          return animMap;
302        }
303    
304    
305        /**
306         * Returns the RealType of the RGB parameter.
307         * @return                  The RealType of the color parameter.  May
308         *                          be <code>null</code>.
309         */
310        public RealType getRGBRealType() {
311            return rgbRealType;
312        }
313    
314        /**
315         * Returns the RealType of the SelectRange parameter.
316         * @return                  The RealType of the select range parameter.  May
317         *                          be <code>null</code>.
318         */
319        public RealType getSelectRealType() {
320            return selectRealType;
321        }
322    
323        protected DataRenderer getDataRenderer() throws VisADException {
324          if (useDefaultRenderer) {
325            return new DefaultRendererJ3D();
326          }
327          else {
328            return new ImageRendererJ3D();
329          }
330        }
331    
332        public void setDefaultRenderer() {
333          useDefaultRenderer = true;
334        }
335    
336        public void setImageRenderer() {
337          useDefaultRenderer = false;
338        }
339    
340        /**
341         * Sets the set of ScalarMap-s of this instance.  The ScalarMap-s of
342         * this instance will be added to the set before the SCALAR_MAP_SET
343         * property is set.  This method fires a PropertyChangeEvent for
344         * SCALAR_MAP_SET with <code>null</code> for the old value and the new
345         * set of ScalarMap-s for the new Value.  Intermediate subclasses that
346         * have their own ScalarMap-s should override this method and invoke
347         * <code>super.setScalarMaps(ScalarMapSet)</code>.
348         * @param maps              The set of ScalarMap-s to be added.
349         * @throws BadMappingException      The RealType of the color parameter
350         *                          has not been set or its ScalarMap is alread in
351         *                          the set.
352         */
353        protected void setScalarMaps(ScalarMapSet maps)
354                throws BadMappingException {
355    
356            if (colorMap == null) {
357                throw new BadMappingException(getClass().getName()
358                                              + ".setScalarMaps(ScalarMapSet): "
359                                              + "Color not yet set");
360            }
361    
362            maps.add(colorMap);
363    
364            if (selectMap != null) {
365    
366                maps.add(selectMap);
367            }
368    
369            super.setScalarMapSet(maps);
370        }
371    
372        /**
373         * This method sets the color palette
374         * according to the color table in argument;
375         * pair this method with setRange(lo,high) to get
376         * a fixed association of color table and range of values.
377         *
378         * @param colorPalette     the color table or color-alpha table desired
379         * @param colorPaletteName name for the color table (can be null)
380         * @throws VisADException  if a core VisAD failure occurs.
381         * @throws RemoteException if a Java RMI failure occurs.
382         */
383        public void setColorPalette(float[][] colorPalette, String name)
384                throws RemoteException, VisADException {
385            if (colorControl != null) {
386                colorControl.setTable(colorPalette);
387            }
388    
389            this.colorPalette = colorPalette;
390            this.colorPaletteName = name;
391        }
392    
393        /**
394         * This method sets the color palette
395         * according to the color table in argument;
396         * pair this method with setRange(lo,high) to get
397         * a fixed association of color table and range of values;
398         * asigns null (doesn't have a name) for the name.
399         *
400         * @param colorPalette     the color table or color-alpha table desired
401         * @throws VisADException  if a core VisAD failure occurs.
402         * @throws RemoteException if a Java RMI failure occurs.
403         */
404        public void setColorPalette(float[][] colorPalette)
405                throws VisADException, RemoteException {
406            setColorPalette(colorPalette, null);
407        }
408    
409        /**
410         * Return the current color palette in this Displayable
411         *
412         * @return a color table float[3][len] or color-alpha table float[4][len]
413         */
414        public float[][] getColorPalette() {
415            return colorPalette;
416        }
417    
418        public String getColorPaletteName() {
419            return colorPaletteName;
420        }
421    
422        /**
423         * Make a color palette representing this color and set it as the
424         * color pallete.
425         *
426         * @param  color  color to use
427         * @throws VisADException     VisAD failure.
428         * @throws RemoteException    Java RMI failure.
429         */
430        public void setColor(Color color) throws RemoteException, VisADException {
431            int       len   = 5;
432            float[][] table = new float[(alphaflag == true)
433                                        ? 4
434                                        : 3][len];
435            for (int m = 0; m < len; m++) {
436                table[0][m] = color.getRed() / 255.f;    // Red amount  
437                table[1][m] = color.getGreen() / 255.f;  // Green
438                table[2][m] = color.getBlue() / 255.f;   // Blue  
439            }
440            setColorPalette(table);
441        }
442    
443        /**
444         * This method sets the color palette to shades of grey.
445         *
446         * @throws VisADException  if a core VisAD failure occurs.
447         * @throws RemoteException if a Java RMI failure occurs.
448         */
449        public final void setGreyPalette()
450                throws RemoteException, VisADException {
451    
452            if (colorControl != null) {
453                colorControl.initGreyWedge();
454                setColorPalette(colorControl.getTable());
455            }
456        }
457    
458        /**
459         * This method with no argument sets the default Vis5D color spectrum.
460         *
461         * @throws VisADException  if a core VisAD failure occurs.
462         * @throws RemoteException if a Java RMI failure occurs.
463         */
464        public final void setVisADPalette()
465                throws RemoteException, VisADException {
466    
467            if (colorControl != null) {
468                colorControl.initVis5D();
469                setColorPalette(colorControl.getTable());
470            }
471        }
472    
473        /**
474         * Set the upper and lower limit of the range values associated
475         * with a color table.
476         *
477         * @param low    the minimun value
478         * @param hi     the maximum value
479         * @deprecated   use setRangeForColor
480         *
481         * @throws RemoteException  Java RMI error
482         * @throws VisADException   problem creating VisAD object
483         */
484        public void setRange(double low, double hi)
485                throws VisADException, RemoteException {
486    
487            setRangeForColor(low, hi);
488        }
489    
490        /**
491         * Set the upper and lower limit of the range values associated
492         * with a color table.
493         *
494         * Matches method name in Contour2DDisplayable
495         *
496         * @param low               The minimum value of the parameter matched to
497         *                          the low end of the color table.
498         * @param hi                The maximum value of the parameter matched to
499         *                          the high end of the color table.
500         *
501         * @exception VisADException   VisAD failure.
502         * @exception RemoteException  Java RMI failure.
503         */
504        public void setRangeForColor(double low, double hi)
505                throws VisADException, RemoteException {
506            lowRange  = low;
507            highRange = hi;
508            if ((colorMap != null) && hasRange()) {
509                colorMap.setRange(low, hi);
510            }
511        }
512    
513        /**
514         * Get the color range
515         *
516         * @return an array of the low and high values for the range
517         * @deprecated  use #getRangeForColor()
518         */
519        public double[] getRangeforColor() {
520            return getRangeForColor();
521        }
522    
523        /**
524         * Get the color range
525         *
526         * @return an array of the low and high values for the range
527         */
528        public double[] getRangeForColor() {
529            return new double[]{ lowRange, highRange };
530        }
531    
532        /**
533         * Apply the correct unit (either the displayUnit or the colorUnit)
534         * to the scalar map
535         *
536         * @param colorMap   ScalarMap to apply to
537         * @param rgbRealType  RealType for default Unit
538         *
539         * @throws RemoteException  Java RMI error
540         * @throws VisADException   problem creating VisAD object
541         */
542        private void applyUnit(ScalarMap colorMap, RealType rgbRealType)
543                throws VisADException, RemoteException {
544            if (useDisplayUnitForColor()) {
545                applyDisplayUnit(colorMap, rgbRealType);
546            } else {
547                applyColorUnit(colorMap, rgbRealType);
548            }
549        }
550    
551    
552        /**
553         * Set the units for the displayed range
554         *
555         * @param unit Unit for display
556         *
557         * @throws RemoteException  Java RMI error
558         * @throws VisADException   problem creating VisAD object
559         */
560        public void setDisplayUnit(Unit unit)
561                throws VisADException, RemoteException {
562            if (useDisplayUnitForColor()) {
563                //Make sure this unit is ok
564                checkUnit(rgbRealType, unit);
565            }
566            super.setDisplayUnit(unit);
567            if (useDisplayUnitForColor()) {
568                applyUnit(colorMap, rgbRealType);
569            }
570        }
571    
572    
573        /**
574         * Set the units for the displayed range
575         *
576         * @param unit Unit for display
577         *
578         * @throws RemoteException  Java RMI error
579         * @throws VisADException   problem creating VisAD object
580         */
581        public void setColorUnit(Unit unit)
582                throws VisADException, RemoteException {
583            if ( !useDisplayUnitForColor()) {
584                //Make sure this unit is ok
585                checkUnit(rgbRealType, unit);
586            }
587            super.setColorUnit(unit);
588            if ( !useDisplayUnitForColor()) {
589                applyUnit(colorMap, rgbRealType);
590            }
591        }
592    
593    
594        /**
595         * Returns whether this Displayable has a valid range (i.e., lowRange and
596         * highRange are both not NaN's
597         *
598         * @return true if range has been set
599         */
600        public boolean hasRange() {
601            return ( !Double.isNaN(lowRange) && !Double.isNaN(highRange));
602        }
603    
604    
605        /**
606         * Sets the size of points in this Displayable.
607         *
608         * @param   pointSize     Size of points (2 = normal)
609         *
610         * @throws VisADException     VisAD failure.
611         * @throws RemoteException    Java RMI failure.
612         */
613        public void setPointSize(float pointSize)
614                throws VisADException, RemoteException {
615    
616            float oldValue;
617    
618            synchronized (this) {
619                oldValue = myPointSize;
620    
621                addConstantMap(new ConstantMap(pointSize, Display.PointSize));
622    
623                myPointSize = pointSize;
624            }
625    
626        }
627    
628        /**
629         * Gets the point size associated with this LineDrawing
630         *
631         * @return  point size
632         */
633        public float getPointSize() {
634            return myPointSize;
635        }
636    
637        /**
638         * Set the type of polygon display that should be used
639         *
640         * @param polygonMode  polygon mode
641         *
642         * @throws RemoteException  Java RMI error
643         * @throws VisADException   problem creating VisAD object
644         */
645        public void setPolygonMode(int polygonMode)
646                throws VisADException, RemoteException {
647            this.polygonMode = polygonMode;
648            addConstantMap(new ConstantMap(convertToVisADPolygonMode(polygonMode),
649                                           Display.PolygonMode));
650        }
651    
652        /**
653         * Converts an RGBDisplayable Polygon mode to the appropriate
654         * (or default) VisAD mode
655         *
656         * @param myMode  polygon mode
657         * @return  Java3D mode
658         */
659        private int convertToVisADPolygonMode(int myMode) {
660            if (visad.util.Util.canDoJava3D()) {
661                switch (myMode) {
662    
663                  case POLYGON_FILL :
664                      return visad.java3d.DisplayImplJ3D.POLYGON_FILL;
665    
666                  case POLYGON_LINE :
667                      return visad.java3d.DisplayImplJ3D.POLYGON_LINE;
668    
669                  case POLYGON_POINT :
670                      return visad.java3d.DisplayImplJ3D.POLYGON_POINT;
671    
672                  default :
673                      return visad.java3d.DisplayImplJ3D.POLYGON_FILL;
674                }
675            } else {
676                return 0;
677            }
678        }
679    
680        /**
681         * Return the type of polygon mode being used
682         *
683         * @return polygon mode
684         */
685        public int getPolygonMode() {
686            return polygonMode;
687        }
688    
689        /**
690         * Set the curved size for textured displays
691         *
692         * @param curvedSize size to use (> 0)
693         *
694         * @throws RemoteException  Java RMI error
695         * @throws VisADException   problem creating VisAD object
696         */
697        public void setCurvedSize(int curvedSize)
698                throws VisADException, RemoteException {
699            this.curvedSize = curvedSize;
700            addConstantMap(makeCurvedSizeMap(curvedSize));
701        }
702    
703        /**
704         * Create the ConstantMap for the texture curve size
705         *
706         * @param curvedSize   size for texture curve
707         * @return  ConstantMap
708         *
709         * @throws RemoteException  Java RMI error
710         * @throws VisADException   problem creating VisAD object
711         */
712        protected ConstantMap makeCurvedSizeMap(int curvedSize)
713                throws VisADException, RemoteException {
714            return new ConstantMap(curvedSize, Display.CurvedSize);
715        }
716    
717        /**
718         * Return the size of a curved texture
719         * @return curved size
720         */
721        public int getCurvedSize() {
722            return curvedSize;
723        }
724    
725        /**
726         * creates the ScalarMap for color and ColorControl for this Displayable.
727         *
728         * @throws VisADException   VisAD failure.
729         * @throws RemoteException  Java RMI failure.
730         */
731        private void setColorMaps() throws RemoteException, VisADException {
732    
733            // ScalarMap is either mapping to Display.RGB (color only)
734            // or to Display.RGBA color plus transparency.
735            if ( !alphaflag) {
736                colorMap = new ScalarMap(rgbRealType, Display.RGB);
737            } else {
738                colorMap = new ScalarMap(rgbRealType, Display.RGBA);
739            }
740    
741            applyUnit(colorMap, rgbRealType);
742    
743            if (hasRange()) {
744               colorMap.setRange(lowRange, highRange);
745            }
746    
747            colorMap.addScalarMapListener(new ScalarMapListener() {
748    
749                public void controlChanged(ScalarMapControlEvent event)
750                        throws RemoteException, VisADException {
751    
752                    int id = event.getId();
753    
754                    if ((id == event.CONTROL_ADDED)
755                            || (id == event.CONTROL_REPLACED)) {
756                        colorControl = (BaseColorControl) colorMap.getControl();
757    
758                        if (colorControl != null) {
759                            if (colorPalette != null) {
760                                colorControl.setTable(colorPalette);
761                            } else {
762                                colorPalette = colorControl.getTable();
763                            }
764                        }
765                    }
766                }
767    
768                public void mapChanged(ScalarMapEvent event)
769                        throws RemoteException, VisADException {
770                    if ((event.getId() == event.AUTO_SCALE) && hasRange()) {
771                      double[] rng = colorMap.getRange();
772                      if (multiSpecCntrl != null) {
773                        multiSpecCntrl.updateRange(new Range(rng));
774                      }
775                    }
776                }
777            });
778            ScalarMapSet maps = getScalarMapSet();  //new ScalarMapSet();
779            maps.add(colorMap);
780            setScalarMapSet(maps);
781        }
782    
783        private void setAnimationMap() throws RemoteException, VisADException {
784          animMap = new ScalarMap(indexRealType, Display.Animation);
785          ScalarMapSet maps = getScalarMapSet();
786          maps.add(animMap);
787          setScalarMapSet(maps);
788        }
789    
790        private void setSelectMap() throws RemoteException, VisADException {
791          animMap = new ScalarMap(indexRealType, Display.SelectValue);
792          ScalarMapSet maps = getScalarMapSet();
793          maps.add(animMap);
794          setScalarMapSet(maps);
795        }
796    
797        /**
798         * Sets the RealType of the select parameter.
799         * @param realType          The RealType of the RGB parameter.  May
800         *                          not be <code>null</code>.
801         * @throws VisADException   VisAD failure.
802         * @throws RemoteException  Java RMI failure.
803         */
804        protected void setSelectRealType(RealType realType)
805                throws RemoteException, VisADException {
806    
807            if ( !realType.equals(selectRealType)) {
808                RealType oldValue = selectRealType;
809                selectRealType = realType;
810                setSelectMaps();
811                if (useDisplayUnitForColor()) {
812                    if ( !isUnitCompatible(selectRealType, getDisplayUnit())) {
813                        setDisplayUnit(null);
814                    }
815                } else {
816                    if ( !isUnitCompatible(selectRealType, getColorUnit())) {
817                        setColorUnit(null);
818                    }
819                }
820            }
821        }
822    
823        /**
824         * Returns whether this Displayable has a valid range
825         * (i.e., lowSelectedRange and highSelectedRange are both not NaN's
826         *
827         * @return true if range has been set
828         */
829        public boolean hasSelectedRange() {
830            return ( !Double.isNaN(lowSelectedRange)
831                     && !Double.isNaN(highSelectedRange));
832        }
833    
834        /**
835         * Set selected range with the range for select
836         *
837         * @param low  low select value
838         * @param hi   hi select value
839         *
840         * @throws RemoteException  Java RMI error
841         * @throws VisADException   problem creating VisAD object
842         */
843        public void setSelectedRange(double low, double hi)
844                throws VisADException, RemoteException {
845    
846            lowSelectedRange  = low;
847            highSelectedRange = hi;
848            if ((selectControl != null) && hasSelectedRange()) {
849                selectControl.setRange(new double[]{ low, hi });
850            }
851    
852        }
853    
854        /**
855         * Set the upper and lower limit of the range values associated
856         * with a color table.
857         *
858         * @param low    the minimun value
859         * @param hi     the maximum value
860         *
861         * @throws RemoteException  Java RMI error
862         * @throws VisADException   problem creating VisAD object
863         */
864        public void setRangeForSelect(double low, double hi)
865                throws VisADException, RemoteException {
866    
867            minSelect = low;
868            maxSelect = hi;
869            if ((selectMap != null) && hasSelectMinMax()) {
870                selectMap.setRange(low, hi);
871            }
872        }
873    
874        /**
875         * Check to see if the range has been set for the select
876         *
877         * @return true if it has
878         */
879        private boolean hasSelectMinMax() {
880            return ( !Double.isNaN(minSelect) && !Double.isNaN(maxSelect));
881        }
882    
883        /**
884         * creates the ScalarMap for SelectRange and control for this Displayable.
885         *
886         * @throws VisADException   VisAD failure.
887         * @throws RemoteException  Java RMI failure.
888         */
889        private void setSelectMaps() throws RemoteException, VisADException {
890    
891            selectMap = new ScalarMap(selectRealType, Display.SelectRange);
892    
893            if (selectRealType.equals(rgbRealType)) {
894                applyUnit(selectMap, selectRealType);
895            }
896    
897            if (hasSelectMinMax()) {
898                selectMap.setRange(minSelect, maxSelect);
899            }
900    
901            selectMap.addScalarMapListener(new ScalarMapListener() {
902    
903                public void controlChanged(ScalarMapControlEvent event)
904                        throws RemoteException, VisADException {
905    
906                    int id = event.getId();
907    
908                    if ((id == event.CONTROL_ADDED)
909                            || (id == event.CONTROL_REPLACED)) {
910                        selectControl = (RangeControl) selectMap.getControl();
911                        if (hasSelectedRange()) {
912                            selectControl.setRange(new double[]{ lowSelectedRange,
913                                                                 highSelectedRange });
914                        }
915                    }
916                }
917    
918                public void mapChanged(ScalarMapEvent event)
919                        throws RemoteException, VisADException {
920                    if ((event.getId() == event.AUTO_SCALE)
921                            && hasSelectMinMax()) {
922                        selectMap.setRange(minSelect, maxSelect);
923                    }
924                }
925            });
926            ScalarMapSet maps = getScalarMapSet();  //new ScalarMapSet();
927            maps.add(selectMap);
928            setScalarMapSet(maps);
929        }
930    
931    }