001    /*
002     * $Id: RGBCompositeControl.java,v 1.11 2012/02/19 17:35:38 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    package edu.wisc.ssec.mcidasv.control;
031    
032    import java.awt.BorderLayout;
033    import java.awt.Container;
034    import java.awt.FlowLayout;
035    import java.awt.GridLayout;
036    import java.awt.event.ActionEvent;
037    import java.awt.event.ActionListener;
038    import java.rmi.RemoteException;
039    import java.util.Iterator;
040    
041    import javax.swing.JButton;
042    import javax.swing.JLabel;
043    import javax.swing.JPanel;
044    import javax.swing.JTextField;
045    
046    import visad.BaseColorControl;
047    import visad.FieldImpl;
048    import visad.FlatField;
049    import visad.FunctionType;
050    import visad.ScalarMap;
051    import visad.ScalarMapControlEvent;
052    import visad.ScalarMapEvent;
053    import visad.ScalarMapListener;
054    import visad.VisADException;
055    import visad.Data;
056    import visad.CoordinateSystem;
057    
058    import visad.georef.MapProjection;
059    
060    import ucar.unidata.data.DataChoice;
061    import ucar.unidata.data.DataSelection;
062    import ucar.unidata.data.grid.GridDataInstance;
063    import ucar.unidata.idv.control.DisplayControlImpl;
064    import ucar.unidata.util.ColorTable;
065    import ucar.unidata.util.LogUtil;
066    import ucar.unidata.util.Range;
067    import ucar.visad.display.DisplayMaster;
068    
069    import edu.wisc.ssec.mcidasv.data.hydra.ImageRGBDisplayable;
070    
071    
072    public class RGBCompositeControl extends DisplayControlImpl {
073    
074       /** Displayable for the data */
075       private ImageRGBDisplayable imageDisplay;
076    
077       private DisplayMaster displayMaster;
078    
079       private ScalarMap redMap = null;
080       private ScalarMap grnMap = null;
081       private ScalarMap bluMap = null;
082    
083       float[][] redTable = null;
084       float[][] grnTable = null;
085       float[][] bluTable = null;
086    
087       final private double[] redRange = new double[] {Double.NaN, Double.NaN};
088       final private double[] grnRange = new double[] {Double.NaN, Double.NaN};
089       final private double[] bluRange = new double[] {Double.NaN, Double.NaN};
090    
091       final double[] initRedRange = new double[] {Double.NaN, Double.NaN};
092       final double[] initGrnRange = new double[] {Double.NaN, Double.NaN};
093       final double[] initBluRange = new double[] {Double.NaN, Double.NaN};
094    
095       private FieldImpl imageField = null;
096       private MapProjection mapProjection = null;
097    
098    
099       private double gamma = 1.0;
100    
101       private double redGamma = 1.0;
102       private double grnGamma = 1.0;
103       private double bluGamma = 1.0;
104    
105       private boolean hasRange = false;
106    
107       private final JTextField gammaTxtFld =
108            new JTextField(Float.toString(1f), 4);
109       private final JTextField redGammaTxtFld =
110            new JTextField(Float.toString(1f), 4);
111       private final JTextField grnGammaTxtFld =
112            new JTextField(Float.toString(1f), 4);
113       private final JTextField bluGammaTxtFld =
114            new JTextField(Float.toString(1f), 4);
115    
116       private final JTextField redLowTxtFld =
117            new JTextField(Float.toString(1f), 10);
118       private final JTextField redHighTxtFld =
119            new JTextField(Float.toString(1f), 10);
120       private final JTextField grnLowTxtFld =
121            new JTextField(Float.toString(1f), 10);
122       private final JTextField grnHighTxtFld =
123            new JTextField(Float.toString(1f), 10);
124       private final JTextField bluLowTxtFld =
125            new JTextField(Float.toString(1f), 10);
126       private final JTextField bluHighTxtFld =
127            new JTextField(Float.toString(1f), 10);
128    
129       public RGBCompositeControl() {
130         super();
131       }
132    
133       public boolean init(DataChoice dataChoice) throws VisADException, RemoteException {
134         displayMaster = getViewManager().getMaster();
135         DataSelection dataSelection = getDataSelection();
136         imageField = (FieldImpl) dataChoice.getData(dataSelection);
137    
138    
139         imageDisplay = new ImageRGBDisplayable("rgb composite", null, false, imageField);
140    
141         Iterator iter = imageDisplay.getScalarMapSet().iterator();
142         while (iter.hasNext()) {
143           ScalarMap map = (ScalarMap) iter.next();
144           double[] datRng = map.getRange();
145           if (map.getScalarName().startsWith("redimage")) {
146                    redMap = map;
147            }
148           if (map.getScalarName().startsWith("greenimage")) {
149                    grnMap = map;
150            }
151           if (map.getScalarName().startsWith("blueimage")) {
152                    bluMap = map;
153            }
154         }
155    
156         if (checkRange()) { //- from unpersistence if true, initialize gui, ScalarMaps
157           double[] redRange = getRedRange();
158           double[] grnRange = getGrnRange();
159           double[] bluRange = getBluRange();
160    
161           initRedRange[0] = redRange[0];
162           initRedRange[1] = redRange[1];
163           initGrnRange[0] = grnRange[0];
164           initGrnRange[1] = grnRange[1];
165           initBluRange[0] = bluRange[0];
166           initBluRange[1] = bluRange[1];
167    
168           redLowTxtFld.setText(Float.toString((float)redRange[0]));
169           redHighTxtFld.setText(Float.toString((float)redRange[1]));
170           grnLowTxtFld.setText(Float.toString((float)grnRange[0]));
171           grnHighTxtFld.setText(Float.toString((float)grnRange[1]));
172           bluLowTxtFld.setText(Float.toString((float)bluRange[0]));
173           bluHighTxtFld.setText(Float.toString((float)bluRange[1]));
174       
175           gammaTxtFld.setText(Float.toString((float)gamma));
176           redGammaTxtFld.setText(Float.toString((float)redGamma));
177           grnGammaTxtFld.setText(Float.toString((float)grnGamma));
178           bluGammaTxtFld.setText(Float.toString((float)bluGamma));
179    
180           redMap.setRange(redRange[0], redRange[1]);
181           grnMap.setRange(grnRange[0], grnRange[1]);
182           bluMap.setRange(bluRange[0], bluRange[1]);
183         } 
184         else {
185           redMap.resetAutoScale();
186           grnMap.resetAutoScale();
187           bluMap.resetAutoScale();
188    
189           redMap.addScalarMapListener(new ColorMapListener(redMap, initRedRange, redRange, redLowTxtFld, redHighTxtFld));
190           grnMap.addScalarMapListener(new ColorMapListener(grnMap, initGrnRange, grnRange, grnLowTxtFld, grnHighTxtFld));
191           bluMap.addScalarMapListener(new ColorMapListener(bluMap, initBluRange, bluRange, bluLowTxtFld, bluHighTxtFld));
192         }
193    
194         setShowInDisplayList(true);
195    
196         addDisplayable(imageDisplay, FLAG_COLORTABLE);
197    
198         return true;
199       }
200    
201       public void initDone() {
202         redTable = ((BaseColorControl)redMap.getControl()).getTable();
203         grnTable = ((BaseColorControl)grnMap.getControl()).getTable();
204         bluTable = ((BaseColorControl)bluMap.getControl()).getTable();
205    
206         float[][] newRedTbl = getZeroOutArray(redTable);
207         float[][] newGrnTbl = getZeroOutArray(grnTable);
208         float[][] newBluTbl = getZeroOutArray(bluTable);
209    
210         for (int k=0; k<redTable[0].length; k++) {
211           newRedTbl[0][k] = (float) Math.pow(redTable[0][k], redGamma);
212           newGrnTbl[1][k] = (float) Math.pow(grnTable[1][k], grnGamma);
213           newBluTbl[2][k] = (float) Math.pow(bluTable[2][k], bluGamma);
214         }
215    
216         try {
217           displayMaster.setDisplayInactive();
218           ((BaseColorControl)redMap.getControl()).setTable(newRedTbl);
219           ((BaseColorControl)grnMap.getControl()).setTable(newGrnTbl);
220           ((BaseColorControl)bluMap.getControl()).setTable(newBluTbl);
221           imageDisplay.loadData(imageField);
222           displayMaster.setDisplayActive();
223         } catch(Exception ex) {
224           LogUtil.logException("setDisplayInactive", ex);
225         }
226       }
227    
228       public MapProjection getDataProjection() {
229         CoordinateSystem cs = null;
230         try {
231           if (imageField instanceof FlatField) {
232             cs = ((FunctionType)imageField.getType()).getDomain().getCoordinateSystem();
233           } 
234           else if (imageField instanceof FieldImpl) {
235             Data dat = imageField.getSample(0, false);
236             if (dat instanceof FlatField) {
237               FlatField img = (FlatField) dat;
238               cs = ((FunctionType)img.getType()).getDomain().getCoordinateSystem();
239             }
240           }
241         }
242         catch (Exception ex) {
243           LogUtil.logException("problem accessing data", ex);
244         }
245    
246         if (cs instanceof MapProjection) mapProjection = (MapProjection) cs;
247    
248         return mapProjection;
249       }
250    
251       boolean checkRange() {
252         if (Double.isNaN(redRange[0]) || Double.isNaN(grnRange[0]) || Double.isNaN(bluRange[0])) {
253           return false;
254         }
255         else {
256           return true;
257         }
258       }
259    
260       private void updateRedRange(double lo, double hi) {
261         redRange[0] = lo;
262         redRange[1] = hi;
263         try {
264           redMap.setRange(lo, hi);
265         } catch (VisADException ex) {
266           LogUtil.logException("redMap.setRange", ex);
267         } catch (RemoteException ex) {
268           LogUtil.logException("redMap.setRange", ex);
269         }
270       }
271    
272       public void setRedRange(double[] range) {
273         redRange[0] = range[0];
274         redRange[1] = range[1];
275       }
276    
277       public double[] getRedRange() {
278         return new double[] {redRange[0], redRange[1]};
279       }
280    
281       private void updateGrnRange(double lo, double hi) {
282         grnRange[0] = lo;
283         grnRange[1] = hi;
284         try {
285           grnMap.setRange(lo, hi);
286         } catch (VisADException ex) {
287           LogUtil.logException("grnMap.setRange", ex);
288         } catch (RemoteException ex) {
289           LogUtil.logException("grnMap.setRange", ex);
290         }
291       }
292    
293       public void setGrnRange(double[] range) {
294         grnRange[0] = range[0];
295         grnRange[1] = range[1];
296       }
297    
298       public double[] getGrnRange() {
299         return new double[] {grnRange[0], grnRange[1]};
300       }
301    
302       private void updateBluRange(double lo, double hi) {
303         bluRange[0] = lo;
304         bluRange[1] = hi;
305         try {
306           bluMap.setRange(lo, hi);
307         } catch (VisADException ex) {
308           LogUtil.logException("bluMap.setRange", ex);
309         } catch (RemoteException ex) {
310           LogUtil.logException("bluMap.setRange", ex);
311         }
312       }
313    
314       public void setBluRange(double[] range) {
315         bluRange[0] = range[0];
316         bluRange[1] = range[1];
317       }
318    
319       public double[] getBluRange() {
320         return new double[] {bluRange[0], bluRange[1]};
321       }
322    
323       public void setRedGamma(double gamma) {
324         redGamma = gamma;
325       }
326    
327       public double getRedGamma() {
328         return redGamma;
329       }
330    
331       public void setGrnGamma(double gamma) {
332         grnGamma = gamma;
333       }
334    
335       public double getGrnGamma() {
336         return grnGamma;
337       }
338    
339       public void setBluGamma(double gamma) {
340         bluGamma = gamma;
341       }
342    
343       public double getBluGamma() {
344         return bluGamma;
345       }
346    
347       public void setGamma(double gamma) {
348         this.gamma = gamma;
349       }
350    
351       public double getGamma() {
352         return gamma;
353       }
354    
355       private void updateGamma(double gamma) {
356         setGamma(gamma);
357         setRedGamma(gamma);
358         setGrnGamma(gamma);
359         setBluGamma(gamma);
360         redGammaTxtFld.setText(Float.toString((float)gamma));
361         grnGammaTxtFld.setText(Float.toString((float)gamma));
362         bluGammaTxtFld.setText(Float.toString((float)gamma));
363            
364         float[][] newRedTbl = getZeroOutArray(redTable);
365         float[][] newGrnTbl = getZeroOutArray(grnTable);
366         float[][] newBluTbl = getZeroOutArray(bluTable);
367    
368         for (int k=0; k<redTable[0].length; k++) {
369           newRedTbl[0][k] = (float) Math.pow(redTable[0][k], gamma);
370           newGrnTbl[1][k] = (float) Math.pow(grnTable[1][k], gamma);
371           newBluTbl[2][k] = (float) Math.pow(bluTable[2][k], gamma);
372         }
373         try {
374           displayMaster.setDisplayInactive();
375           ((BaseColorControl)redMap.getControl()).setTable(newRedTbl);
376           ((BaseColorControl)grnMap.getControl()).setTable(newGrnTbl);
377           ((BaseColorControl)bluMap.getControl()).setTable(newBluTbl);
378           displayMaster.setDisplayActive();
379         } catch(Exception ex) {
380           LogUtil.logException("setDisplayInactive", ex);
381         }
382       }
383    
384       private void updateRedGamma(double gamma) {
385         setRedGamma(gamma);
386    
387         float[][] newRedTbl = getZeroOutArray(redTable);
388    
389         for (int k=0; k<redTable[0].length; k++) {
390           newRedTbl[0][k] = (float) Math.pow(redTable[0][k], gamma);
391         }
392    
393         try {
394           displayMaster.setDisplayInactive();
395           ((BaseColorControl)redMap.getControl()).setTable(newRedTbl);
396           displayMaster.setDisplayActive();
397         } catch(Exception ex) {
398           LogUtil.logException("setDisplayInactive", ex);
399         }
400       }
401    
402       private void updateGrnGamma(double gamma) {
403         setGrnGamma(gamma);
404    
405         float[][] newGrnTbl = getZeroOutArray(grnTable);
406         for (int k=0; k<grnTable[0].length; k++) {
407           newGrnTbl[1][k] = (float) Math.pow(grnTable[1][k], gamma);
408         }
409    
410         try {
411           displayMaster.setDisplayInactive();
412           ((BaseColorControl)grnMap.getControl()).setTable(newGrnTbl);
413           displayMaster.setDisplayActive();
414         } catch(Exception ex) {
415           LogUtil.logException("setDisplayInactive", ex);
416         }
417       }
418    
419       private void updateBluGamma(double gamma) {
420         setBluGamma(gamma);
421    
422         float[][] newBluTbl = getZeroOutArray(bluTable);
423         for (int k=0; k<bluTable[0].length; k++) {
424           newBluTbl[2][k] = (float) Math.pow(bluTable[2][k], gamma);
425         }
426    
427         try {
428           displayMaster.setDisplayInactive();
429           ((BaseColorControl)bluMap.getControl()).setTable(newBluTbl);
430           displayMaster.setDisplayActive();
431         } catch(Exception ex) {
432           LogUtil.logException("setDisplayInactive", ex);
433         }
434       }
435    
436       public float[][] getZeroOutArray(float[][] array) {
437         float[][] newArray = new float[array.length][array[0].length];
438         for (int i=0; i<newArray.length; i++) {
439           for (int j=0; j<newArray[0].length; j++) {
440             newArray[i][j] = 0f;
441           }
442         }
443         return newArray;
444       }
445    
446       protected ColorTable getInitialColorTable() {
447         return getDisplayConventions().getParamColorTable("image");
448       }
449    
450       public Container doMakeContents() {
451    
452         JPanel bigPanel = new JPanel(new BorderLayout());
453         JPanel subPanel = new JPanel(new GridLayout(4,1));
454    
455         JPanel gammaPanel = new JPanel(new FlowLayout());
456              final JLabel nameLabel = new JLabel("Gamma: ");
457    
458              gammaTxtFld.addActionListener(new ActionListener() {
459                  public void actionPerformed(ActionEvent e) {
460                      String tmp = gammaTxtFld.getText().trim();
461                      updateGamma(Double.valueOf(tmp));
462                  }
463              });
464    
465         gammaPanel.add(nameLabel);
466         gammaPanel.add(gammaTxtFld);
467    
468         JPanel redPanel = new JPanel(new FlowLayout());
469         redPanel.add(new JLabel("Red range: "));
470       
471         redLowTxtFld.addActionListener(new ActionListener() {
472             public void actionPerformed(ActionEvent e) {
473                String tmp = redLowTxtFld.getText().trim();
474                updateRedRange(Double.valueOf(tmp), redRange[1]);
475             }
476         });
477         redPanel.add(redLowTxtFld);
478         redHighTxtFld.addActionListener(new ActionListener() {
479             public void actionPerformed(ActionEvent e) {
480                String tmp = redHighTxtFld.getText().trim();
481                updateRedRange(redRange[0], Double.valueOf(tmp));
482             }
483         });
484         redPanel.add(redHighTxtFld);
485    
486         redGammaTxtFld.addActionListener(new ActionListener() {
487             public void actionPerformed(ActionEvent e) {
488                 String tmp = redGammaTxtFld.getText().trim();
489                 updateRedGamma(Double.valueOf(tmp));
490             }
491         });
492         redPanel.add(new JLabel("Gamma:"));
493         redPanel.add(redGammaTxtFld);
494    
495         JButton button = new JButton("reset");
496         redPanel.add(button);
497         button.addActionListener(new ActionListener() {
498           public void actionPerformed(ActionEvent e) {
499             updateRedRange(initRedRange[0], initRedRange[1]);
500             redRange[0] = initRedRange[0];
501             redRange[1] = initRedRange[1];
502             redLowTxtFld.setText(Float.toString((float)redRange[0]));
503             redHighTxtFld.setText(Float.toString((float)redRange[1]));
504           }
505         });
506    
507         JPanel grnPanel = new JPanel(new FlowLayout());
508         grnPanel.add(new JLabel("Green range: "));
509       
510         grnLowTxtFld.addActionListener(new ActionListener() {
511             public void actionPerformed(ActionEvent e) {
512                String tmp = grnLowTxtFld.getText().trim();
513                updateGrnRange(Double.valueOf(tmp), grnRange[1]);
514             }
515         });
516         grnPanel.add(grnLowTxtFld);
517         grnHighTxtFld.addActionListener(new ActionListener() {
518             public void actionPerformed(ActionEvent e) {
519                String tmp = grnHighTxtFld.getText().trim();
520                updateGrnRange(grnRange[0], Double.valueOf(tmp));
521             }
522         });
523         grnPanel.add(grnHighTxtFld);
524    
525         grnGammaTxtFld.addActionListener(new ActionListener() {
526             public void actionPerformed(ActionEvent e) {
527                 String tmp = grnGammaTxtFld.getText().trim();
528                 updateGrnGamma(Double.valueOf(tmp));
529             }
530         });
531         grnPanel.add(new JLabel("Gamma:"));
532         grnPanel.add(grnGammaTxtFld);
533    
534    
535         button = new JButton("reset");
536         grnPanel.add(button);
537         button.addActionListener(new ActionListener() {
538           public void actionPerformed(ActionEvent e) {
539             updateGrnRange(initGrnRange[0], initGrnRange[1]);
540             grnRange[0] = initGrnRange[0];
541             grnRange[1] = initGrnRange[1];
542             grnLowTxtFld.setText(Float.toString((float)grnRange[0]));
543             grnHighTxtFld.setText(Float.toString((float)grnRange[1]));
544           }
545         });
546    
547    
548    
549         JPanel bluPanel = new JPanel(new FlowLayout());
550         bluPanel.add(new JLabel("Blue range: "));
551       
552         bluLowTxtFld.addActionListener(new ActionListener() {
553             public void actionPerformed(ActionEvent e) {
554                String tmp = bluLowTxtFld.getText().trim();
555                updateBluRange(Double.valueOf(tmp), bluRange[1]);
556             }
557         });
558         bluPanel.add(bluLowTxtFld);
559         bluHighTxtFld.addActionListener(new ActionListener() {
560             public void actionPerformed(ActionEvent e) {
561                String tmp = bluHighTxtFld.getText().trim();
562                updateBluRange(bluRange[0], Double.valueOf(tmp));
563             }
564         });
565         bluPanel.add(bluHighTxtFld);
566    
567         bluGammaTxtFld.addActionListener(new ActionListener() {
568             public void actionPerformed(ActionEvent e) {
569                 String tmp = bluGammaTxtFld.getText().trim();
570                 updateBluGamma(Double.valueOf(tmp));
571             }
572         });
573         bluPanel.add(new JLabel("Gamma:"));
574         bluPanel.add(bluGammaTxtFld);
575    
576         button = new JButton("reset");
577         bluPanel.add(button);
578         button.addActionListener(new ActionListener() {
579           public void actionPerformed(ActionEvent e) {
580             updateBluRange(initBluRange[0], initBluRange[1]);
581             bluRange[0] = initBluRange[0];
582             bluRange[1] = initBluRange[1];
583             bluLowTxtFld.setText(Float.toString((float)bluRange[0]));
584             bluHighTxtFld.setText(Float.toString((float)bluRange[1]));
585           }
586         });
587    
588    
589         subPanel.add(redPanel);
590         subPanel.add(grnPanel);
591         subPanel.add(bluPanel);
592         subPanel.add(gammaPanel);
593    
594         bigPanel.add(subPanel, BorderLayout.NORTH);
595    
596         return bigPanel;
597       }
598    
599      private class ColorMapListener implements ScalarMapListener
600      {
601        ScalarMap clrMap;
602    
603        double[] range = null;
604        double[] initRange = null;
605    
606        JTextField lowTxtFld;
607        JTextField highTxtFld;
608    
609        ColorMapListener(ScalarMap clrMap, double[] initRange, double[] range, JTextField lowTxtFld, JTextField highTxtFld) {
610          this.clrMap = clrMap;
611          this.lowTxtFld = lowTxtFld;
612          this.highTxtFld = highTxtFld;
613          this.range = range;
614          this.initRange = initRange;
615        }
616    
617    
618        public void controlChanged(ScalarMapControlEvent event) throws RemoteException, VisADException {
619        }
620    
621        public void mapChanged(ScalarMapEvent event) throws RemoteException, VisADException {       
622          if (event.getId() == event.AUTO_SCALE) {
623                double[] rng = clrMap.getRange();
624                boolean shouldRemove = false;
625                //Ghansham: decide whether it is first time. The cleaner way
626                if (!Double.isNaN(rng[0]) && !Double.isNaN(rng[1]) && Double.isNaN(initRange[0]) && Double.isNaN(initRange[1])) {
627                    shouldRemove = true;
628                }
629                range[0] = rng[0];
630                range[1] = rng[1];
631                initRange[0] = rng[0];
632                initRange[1] = rng[1];
633                lowTxtFld.setText(Float.toString((float)rng[0]));
634                highTxtFld.setText(Float.toString((float)rng[1]));
635                //Ghansham:If its first time remove the scalarmaplistener and setRange manually to disable autscaling of the scalarmap
636                if(shouldRemove) {
637                    clrMap.removeScalarMapListener(this);
638                //-Lock out auto-scaling
639                    clrMap.disableAutoScale();
640                }
641          }
642          else if (event.getId() == event.MANUAL) {
643                double[] rng = clrMap.getRange();
644                range[0] = rng[0];
645                range[1] = rng[1];
646          }
647        }
648      }
649    
650    
651    }