001/*
002 * $Id: HydraImageProbe.java,v 1.12 2011/03/24 16:06:32 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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
031package edu.wisc.ssec.mcidasv.control;
032
033import java.awt.Color;
034import java.rmi.RemoteException;
035import java.text.DecimalFormat;
036
037import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
038
039import ucar.unidata.idv.control.LineProbeControl;
040import ucar.unidata.util.LogUtil;
041import ucar.visad.display.TextDisplayable;
042import visad.CellImpl;
043import visad.Data;
044import visad.DataReference;
045import visad.DataReferenceImpl;
046import visad.FlatField;
047import visad.MathType;
048import visad.Real;
049import visad.RealTuple;
050import visad.RealTupleType;
051import visad.Text;
052import visad.TextType;
053import visad.Tuple;
054import visad.TupleType;
055import visad.VisADException;
056import visad.georef.EarthLocationTuple;
057
058public 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}