001    /*
002     * $Id: HydraImageProbe.java,v 1.13 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    
031    package edu.wisc.ssec.mcidasv.control;
032    
033    import java.awt.Color;
034    import java.rmi.RemoteException;
035    import java.text.DecimalFormat;
036    
037    import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
038    
039    import ucar.unidata.idv.control.LineProbeControl;
040    import ucar.unidata.util.LogUtil;
041    import ucar.visad.display.TextDisplayable;
042    import visad.CellImpl;
043    import visad.Data;
044    import visad.DataReference;
045    import visad.DataReferenceImpl;
046    import visad.FlatField;
047    import visad.MathType;
048    import visad.Real;
049    import visad.RealTuple;
050    import visad.RealTupleType;
051    import visad.Text;
052    import visad.TextType;
053    import visad.Tuple;
054    import visad.TupleType;
055    import visad.VisADException;
056    import visad.georef.EarthLocationTuple;
057    
058    public class HydraImageProbe extends LineProbeControl {
059    
060        private static final TupleType TUPTYPE = makeTupleType();
061    
062        private DataReference positionRef = null;
063    
064        private DataReference spectrumRef = null;
065    
066        private Color currentColor = Color.MAGENTA;
067    
068        private RealTuple currentPosition = null;
069    
070        private Tuple locationValue = null;
071    
072        private MultiSpectralDisplay display = null;
073    
074        private TextDisplayable valueDisplay = null;
075    
076        public HydraImageProbe() throws VisADException, RemoteException {
077            super();
078    
079            currentPosition = new RealTuple(RealTupleType.Generic2D);
080    
081            spectrumRef = new DataReferenceImpl(hashCode() + "_spectrumRef");
082            positionRef = new DataReferenceImpl(hashCode() + "_positionRef");
083    
084            valueDisplay = createValueDisplayer(currentColor);
085    
086            new Updater();
087        }
088    
089        public void setDisplay(final MultiSpectralDisplay disp) throws VisADException, RemoteException {
090            display = disp;
091            display.addRef(spectrumRef, currentColor);
092        }
093    
094        // triggered for both position and color changes.
095        protected void probePositionChanged(final RealTuple newPos) {
096            if (display == null)
097                return;
098    
099            if (!currentPosition.equals(newPos)) {
100                updatePosition(newPos);
101                updateLocationValue();
102                updateSpectrum();
103                currentPosition = newPos;
104            } 
105    
106            Color tmp = getColor();
107            if (!currentColor.equals(tmp)) {
108                updateSpectrumColor(tmp);
109                currentColor = tmp;
110            }
111        }
112    
113        public RealTuple getCurrentPosition() {
114            return currentPosition;
115        }
116        
117        public Color getCurrentColor() {
118            return currentColor;
119        }
120        
121        public TextDisplayable getValueDisplay() {
122            return valueDisplay;
123        }
124    
125        public DataReference getSpectrumRef() {
126            return spectrumRef;
127        }
128    
129        public DataReference getPositionRef() {
130            return positionRef;
131        }
132    
133        public Tuple getLocationValue() {
134            return locationValue;
135        }
136    
137        private void updateLocationValue() {
138            Tuple tup = null;
139    
140            try {
141                RealTuple location = (RealTuple)positionRef.getData();
142                if (location == null)
143                    return;
144    
145                FlatField image = (FlatField)display.getImageDisplay().getData();
146                if (image == null)
147                    return;
148    
149                double[] vals = location.getValues();
150                if (vals[1] < -180)
151                    vals[1] += 360f;
152    
153                if (vals[1] > 180)
154                    vals[1] -= 360f;
155    
156                RealTuple lonLat = new RealTuple(RealTupleType.SpatialEarth2DTuple, new double[] { vals[1], vals[0] });
157                Real val = (Real)image.evaluate(lonLat, Data.NEAREST_NEIGHBOR, Data.NO_ERRORS);
158                float fval = (float)val.getValue();
159                tup = new Tuple(TUPTYPE, new Data[] { lonLat, new Text(TextType.Generic, Float.toString(fval)) });
160                valueDisplay.setData(tup);
161            } catch (Exception e) {
162                LogUtil.logException("HydraImageProbe.updateLocationValue", e);
163            }
164    
165            if (tup != null)
166                locationValue = tup;
167        }
168    
169        public void forceUpdateSpectrum() {
170            updateLocationValue();
171            updateSpectrum();
172            updatePosition(currentPosition);
173        }
174    
175        private void updateSpectrum() {
176            try {
177                RealTuple tmp = (RealTuple)positionRef.getData();
178                FlatField spectrum = display.getMultiSpectralData().getSpectrum(tmp);
179                spectrumRef.setData(spectrum);
180            } catch (Exception e) {
181                LogUtil.logException("HydraImageProbe.updateSpectrum", e);
182            }
183        }
184    
185        protected void updatePosition(final RealTuple position) {
186            double[] vals = position.getValues();
187            try {
188                EarthLocationTuple elt = (EarthLocationTuple)boxToEarth(
189                    new double[] { vals[0], vals[1], 1.0 });
190    
191                positionRef.setData(elt.getLatLonPoint());
192            } catch (Exception e) {
193                LogUtil.logException("HydraImageProbe.updatePosition", e);
194            }
195        }
196    
197        private void updateSpectrumColor(final Color color) {
198            try {
199                display.updateRef(spectrumRef, color);
200                valueDisplay.setColor(color);
201            } catch (Exception e) {
202                LogUtil.logException("HydraImageProbe.updateColor", e);
203            }
204        }
205    
206        private static TextDisplayable createValueDisplayer(final Color color) 
207            throws VisADException, RemoteException 
208        {
209            DecimalFormat fmt = new DecimalFormat();
210            fmt.setMaximumIntegerDigits(3);
211            fmt.setMaximumFractionDigits(1);
212    
213            TextDisplayable td = new TextDisplayable(TextType.Generic);
214            td.setLineWidth(2f);
215            td.setColor(color);
216            td.setNumberFormat(fmt);
217    
218            return td;
219        }
220    
221        private static TupleType makeTupleType() {
222            TupleType t = null;
223            try {
224                t = new TupleType(new MathType[] {RealTupleType.SpatialEarth2DTuple, 
225                                                  TextType.Generic});
226            } catch (Exception e) {
227                LogUtil.logException("HydraImageProbe.makeTupleType", e);
228            }
229            return t;
230        }
231    
232        private class Updater extends CellImpl {
233            public Updater() throws VisADException, RemoteException {
234                this.addReference(positionRef);
235            }
236            
237            public void doAction() {
238    
239            }
240        }
241    }