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