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