001    /*
002     * $Id: StormIntensityControl.java,v 1.1 2012/01/04 20:39:38 tommyj 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.cyclone;
032    
033    import java.awt.Component;
034    import java.awt.Container;
035    import java.awt.Dimension;
036    import java.awt.Point;
037    import java.awt.Toolkit;
038    import java.awt.event.ActionEvent;
039    import java.awt.event.ActionListener;
040    import java.awt.event.InputEvent;
041    import java.rmi.RemoteException;
042    import java.util.ArrayList;
043    import java.util.List;
044    import java.util.Vector;
045    
046    import javax.swing.JButton;
047    import javax.swing.JComboBox;
048    import javax.swing.JComponent;
049    import javax.swing.JDialog;
050    import javax.swing.JEditorPane;
051    import javax.swing.JLabel;
052    import javax.swing.JPanel;
053    import javax.swing.JScrollPane;
054    import javax.swing.JTextField;
055    
056    import ucar.unidata.data.DataChoice;
057    import ucar.unidata.data.DataInstance;
058    import ucar.unidata.data.DataSourceImpl;
059    import ucar.unidata.data.DataUtil;
060    import ucar.unidata.data.grid.GridUtil;
061    import ucar.unidata.data.imagery.AddeImageDataSource;
062    import ucar.unidata.data.imagery.AddeImageDescriptor;
063    import ucar.unidata.data.imagery.ImageDataSource;
064    import ucar.unidata.idv.DisplayInfo;
065    import ucar.unidata.idv.control.DisplayControlImpl;
066    import ucar.unidata.ui.LatLonWidget;
067    import ucar.unidata.util.GuiUtils;
068    import ucar.unidata.util.Misc;
069    import ucar.unidata.util.ObjectListener;
070    import ucar.unidata.view.geoloc.NavigatedDisplay;
071    import ucar.visad.Util;
072    import ucar.visad.display.Animation;
073    import ucar.visad.display.PointProbe;
074    import ucar.visad.quantities.AirTemperature;
075    import visad.CommonUnit;
076    import visad.DateTime;
077    import visad.DisplayEvent;
078    import visad.FieldImpl;
079    import visad.FlatField;
080    import visad.Real;
081    import visad.RealTuple;
082    import visad.RealTupleType;
083    import visad.Set;
084    import visad.VisADException;
085    import visad.georef.EarthLocation;
086    import visad.georef.LatLonPoint;
087    import visad.util.DataUtility;
088    import edu.wisc.ssec.mcidas.AreaDirectory;
089    import edu.wisc.ssec.mcidasv.data.cyclone.StormAODT;
090    import edu.wisc.ssec.mcidasv.data.cyclone.StormAODTInfo;
091    import edu.wisc.ssec.mcidasv.data.cyclone.StormAODTUtil;
092    
093    /**
094     * Created by IntelliJ IDEA. User: yuanho Date: Mar 10, 2009 Time: 1:03:56 PM To
095     * change this template use File | Settings | File Templates.
096     */
097    
098    public class StormIntensityControl extends DisplayControlImpl {
099    
100            /** _more_ */
101            private LatLonWidget latLonWidget;
102    
103            /** _more_ */
104            private JEditorPane textComp;
105    
106            /** _more_ */
107            private LatLonPoint probeLocation;
108    
109            /** the probe */
110            private PointProbe probe;
111    
112            /** _more_ */
113            private DataChoice choice;
114    
115            /** _more_ */
116            private boolean running = false;
117    
118            /** _more_ */
119            private boolean runOnClick = false;
120    
121            /** _more_ */
122            private JButton aodtBtn;
123    
124            /**
125             * _more_
126             */
127            public StormIntensityControl() {
128            }
129    
130            /**
131             * _more_
132             * 
133             * @param choice
134             *            _more_
135             * 
136             * @return _more_
137             * 
138             * @throws RemoteException
139             *             _more_
140             * @throws VisADException
141             *             _more_
142             */
143            public boolean init(DataChoice choice) throws VisADException,
144                            RemoteException {
145                    if (!super.init(choice)) {
146                            return false;
147                    }
148                    this.choice = choice;
149    
150                    // probe = new SelectorPoint ("",new
151                    // RealTuple(RealTupleType.SpatialEarth3DTuple,
152                    // new double[] {0,0,0}));
153    
154                    probe = new PointProbe(new RealTuple(RealTupleType.SpatialEarth3DTuple,
155                                    new double[] { 0, 0, 0 }));
156    
157                    probe.setManipulable(false);
158                    probe.setVisible(false);
159                    probe.setAutoSize(true);
160    
161                    probe.setPointSize(getDisplayScale());
162                    addDisplayable(probe, FLAG_COLOR);
163    
164                    setContents(doMakeContents());
165                    updateProbeLocation();
166                    return true;
167            }
168    
169            /** _more_ */
170            private JComboBox domainBox;
171    
172            /** _more_ */
173            private int domainIndex = 0;
174    
175            /** _more_ */
176            private JComboBox oceanBox;
177    
178            /** _more_ */
179            private int oceanIndex = 0;
180    
181            /** _more_ */
182            private JComboBox sceneBox;
183    
184            /** _more_ */
185            private int sceneIndex = 0;
186    
187            /** _more_ */
188            private String[] ocean = { "Atlantic", "Pacific", "Indian" };
189    
190            /** _more_ */
191            private String text;
192    
193            /**
194             * _more_
195             * 
196             * @return _more_
197             */
198            public Container doMakeContents() {
199                    latLonWidget = new LatLonWidget(GuiUtils.makeActionListener(this,
200                                    "latLonWidgetChanged", null));
201                    JPanel latlonPanel = GuiUtils.hbox(Misc.newList(latLonWidget));
202    
203                    domainBox = new JComboBox(new Vector(Misc.newList("Ocean", "Land")));
204                    domainBox.setSelectedIndex(domainIndex);
205                    domainBox.addActionListener(new ActionListener() {
206                            public void actionPerformed(ActionEvent ae) {
207                                    domainIndex = domainBox.getSelectedIndex();
208                            }
209                    });
210                    domainBox.setToolTipText("Domain selection for Ocean or Land.");
211    
212                    oceanBox = new JComboBox(new Vector(Misc.newList("Atlantic", "Pacific",
213                                    "Indian")));
214                    oceanBox.setSelectedIndex(oceanIndex);
215                    oceanBox.addActionListener(new ActionListener() {
216                            public void actionPerformed(ActionEvent ae) {
217                                    oceanIndex = oceanBox.getSelectedIndex();
218                            }
219                    });
220                    oceanBox.setToolTipText("Ocean Selection Atlantic, Pacific, or Indian");
221    
222                    sceneBox = new JComboBox(new Vector(Misc.newList(" COMPUTED")));
223                    sceneBox.setSelectedIndex(sceneIndex);
224                    sceneBox.addActionListener(new ActionListener() {
225                            public void actionPerformed(ActionEvent ae) {
226                                    sceneIndex = sceneBox.getSelectedIndex();
227                            }
228                    });
229                    sceneBox.setToolTipText("Only computed scene type available");
230    
231                    aodtBtn = new JButton("Run Analysis");
232                    aodtBtn.addActionListener(new ActionListener() {
233                            public void actionPerformed(ActionEvent ae) {
234                                    doAnalysis();
235                            }
236                    });
237                    JComponent btn = GuiUtils.hbox(aodtBtn, GuiUtils.makeCheckbox(
238                                    "Run On Click", this, "runOnClick"));
239    
240                    textComp = new JEditorPane();
241    
242                    textComp.setEditable(false);
243                    textComp.setContentType("text/html");
244                    textComp.setPreferredSize(new Dimension(300, 180));
245                    // GuiUtils.setFixedWidthFont(textComp);
246                    textComp.setEditable(false);
247    
248                    JScrollPane textScroller = new JScrollPane(textComp);
249                    textScroller
250                                    .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
251                    textScroller.setPreferredSize(new Dimension(300, 180));
252    
253                    JComponent textHolder = GuiUtils.topCenter(new JLabel("Result:"),
254                                    textScroller);
255    
256                    GuiUtils.tmpInsets = GuiUtils.INSETS_5;
257                    JComponent widgets = GuiUtils.formLayout(new Component[] {
258                                    GuiUtils.rLabel("Location:"),
259                                    GuiUtils.left(latlonPanel),
260                                    GuiUtils.rLabel("Domain:"),
261                                    GuiUtils.left(GuiUtils.hbox(new Component[] { domainBox,
262                                                    new JLabel("Ocean Selection:"), oceanBox,
263                                                    new JLabel("Scene Type:"), sceneBox }, 5)),
264                                    GuiUtils.filler(), GuiUtils.left(btn) });
265                    // JPanel htmlPanel = GuiUtils.hbox( htmlScroller);
266    
267                    // JPanel controls =
268                    // GuiUtils.topCenterBottom(latlonPanel,widgets,textHolder);
269                    JPanel controls = GuiUtils.topCenter(widgets, textHolder);
270    
271                    return controls;
272            }
273    
274            /**
275             * _more_
276             */
277            public void latLonWidgetChanged() {
278                    try {
279                            System.err.println("widget changed");
280                            String message = latLonWidget.isValidValues();
281                            if (message != null) {
282                                    userMessage(message);
283                                    return;
284                            }
285    
286                            probeLocation = ucar.visad.Util.makeEarthLocation(
287                                            latLonWidget.getLat(), latLonWidget.getLon())
288                                            .getLatLonPoint();
289                    } catch (Exception e) {
290                            logException("Handling LatLonWidget changed", e);
291                    }
292    
293            }
294    
295            /**
296             * _more_
297             * 
298             * @return _more_
299             */
300            protected boolean shouldAddDisplayListener() {
301                    return true;
302            }
303    
304            /**
305             * _more_
306             * 
307             * @return _more_
308             */
309            protected boolean shouldAddControlListener() {
310                    return true;
311            }
312    
313            /**
314             * Should we handle display events
315             * 
316             * @return Ok to handle events
317             */
318            protected boolean canHandleEvents() {
319                    if (!getHaveInitialized() || (getMakeWindow() && !getWindowVisible())) {
320                            return false;
321                    }
322                    return isGuiShown();
323            }
324    
325            /**
326             * Listen for DisplayEvents
327             * 
328             * @param event
329             *            The event
330             */
331            public void handleDisplayChanged(DisplayEvent event) {
332                    super.handleDisplayChanged(event);
333    
334                    if (!canHandleEvents()) {
335                            return;
336                    }
337    
338                    int id = event.getId();
339                    InputEvent inputEvent = event.getInputEvent();
340    
341                    try {
342                            if (id == DisplayEvent.MOUSE_PRESSED) {
343                                    if (!isLeftButtonDown(event)) {
344                                            return;
345                                    }
346                                    probeLocation = toEarth(event).getLatLonPoint();
347                                    updateProbeLocation();
348                                    if (runOnClick) {
349                                            doAnalysis();
350                                    }
351                            }
352                    } catch (Exception e) {
353                            logException("Handling display event changed", e);
354                    }
355    
356            }
357    
358            /**
359             * _more_
360             */
361            private void updateProbeLocation() {
362                    try {
363                            if (probeLocation == null) {
364                                    return;
365                            }
366                            double lon = probeLocation.getLongitude().getValue(
367                                            CommonUnit.degree);
368                            double lat = probeLocation.getLatitude()
369                                            .getValue(CommonUnit.degree);
370                            probe.setPosition(new RealTuple(RealTupleType.SpatialEarth3DTuple,
371                                            new double[] { lon, lat, 0 }));
372    
373                            // probe.setPoint(new RealTuple(RealTupleType.SpatialEarth3DTuple,
374                            // new double[] {lon,
375                            // lat,0}));
376    
377                            probe.setVisible(true);
378    
379                            if (latLonWidget != null) {
380                                    latLonWidget.setLat(getDisplayConventions()
381                                                    .formatLatLon(
382                                                                    probeLocation.getLatitude().getValue(
383                                                                                    CommonUnit.degree)));
384    
385                                    latLonWidget.setLon(getDisplayConventions().formatLatLon(
386                                                    probeLocation.getLongitude()
387                                                                    .getValue(CommonUnit.degree)));
388    
389                            }
390                            // Misc.run(this, "doAnalysis");
391    
392                    } catch (Exception e) {
393                            logException("Handling probe changed", e);
394                    }
395            }
396    
397            /**
398             * _more_
399             */
400            private void doAnalysis() {
401                    if (running) {
402                            return;
403                    }
404                    running = true;
405                    aodtBtn.setEnabled(false);
406                    aodtBtn.setText("Running");
407    
408                    Misc.run(new Runnable() {
409                            public void run() {
410                                    doAnalysisInner();
411                                    running = false;
412                                    aodtBtn.setEnabled(true);
413                            }
414                    });
415    
416            }
417    
418            /**
419             * _more_
420             */
421            private void doAnalysisInner() {
422                    FlatField ffield = null;
423                    StormAODT sint = new StormAODT();
424                    int sid = 0;
425                    int channel = 0;
426    
427                    if (probeLocation == null) {
428                            return;
429                    }
430                    // Set timeset = null;
431                    RealTuple timeTuple = null;
432                    List sources = new ArrayList();
433                    Real tt = null;
434                    DateTime dat = null;
435                    boolean isTemp = false;
436                    choice.getDataSources(sources);
437                    try {
438                            List infos = getDisplayInfos();
439                            DataInstance de = getDataInstance();
440                            DisplayInfo displayInfo = (DisplayInfo) infos.get(0);
441    
442                            Animation anime = displayInfo.getViewManager().getAnimation();
443                            Set timeSet = anime.getSet();
444                            int pos = anime.getCurrent();
445                            ffield = DataUtil.getFlatField(de.getData());
446                            DataSourceImpl dsi = (DataSourceImpl) sources.get(0);
447    
448                            if (dsi instanceof AddeImageDataSource) {
449                                    ImageDataSource dds = (ImageDataSource) sources.get(0);
450                                    List imageLists = dds.getImageList();
451    
452                                    AddeImageDescriptor aid = (AddeImageDescriptor) imageLists
453                                                    .get(pos);
454                                    AreaDirectory ad = aid.getDirectory();
455                                    sid = ad.getSensorID();
456                                    int[] bands = ad.getBands();
457                                    channel = bands[0];
458    
459                                    isTemp = Util
460                                                    .isCompatible(ffield, AirTemperature.getRealType());
461                            } else {
462                                    channel = 4;
463                                    sid = 70;
464                                    String name = ffield.getSample(0).getType().prettyString();
465                                    if (!name.contains("IR")) {
466                                            text = "Storm intensity analysis only running over Infrared field";
467                                            textComp.setText(text);
468                                            return;
469                                    }
470                            }
471    
472                            timeTuple = DataUtility.getSample(timeSet, pos);
473                            tt = (Real) timeTuple.getComponent(0);
474                            dat = new DateTime(tt);
475                    } catch (VisADException e) {
476                            logException("Handling data", e);
477                            return;
478                    } catch (RemoteException f) {
479                    }
480    
481                    String shortName = choice.getName();
482    
483                    float cenlat = (float) probeLocation.getLatitude().getValue();
484                    float cenlon = (float) probeLocation.getLongitude().getValue();
485                    double curtime = dat.getValue();
486    
487                    String g_domain = ocean[oceanIndex]; // "ATL";
488                    int cursat = 0;
489                    int posm = 1;
490    
491                    if (domainIndex == 1) {
492                            text = "Storm intensity analysis not available over land";
493                            textComp.setText(text);
494                            return;
495                    }
496    
497                    StormAODTInfo.IRData result = sint.aodtv72_drive(ffield, cenlat,
498                                    cenlon, posm, curtime, cursat, g_domain, sid, channel, isTemp);
499                    text = StormAODTUtil.aodtv72_textscreenoutput(result,
500                                    getDisplayConventions().getLatLonFormat());
501                    textComp.setText(text);
502            }
503    
504            /**
505             * _more_
506             * 
507             * @param data
508             *            _more_
509             * 
510             * @return _more_
511             * 
512             * @throws RemoteException
513             *             _more_
514             * @throws VisADException
515             *             _more_
516             */
517            protected FlatField getFlatField(FieldImpl data) throws VisADException,
518                            RemoteException {
519                    FlatField ff = null;
520                    if (GridUtil.isSequence(data)) {
521                            ff = (FlatField) data.getSample(0);
522                    } else {
523                            ff = (FlatField) data;
524                    }
525                    return ff;
526            }
527    
528            /**
529             * Map the screen x/y of the event to an earth location
530             * 
531             * @param event
532             *            The event
533             * 
534             * @return The earth location
535             * 
536             * @throws java.rmi.RemoteException
537             *             When bad things happen
538             * @throws visad.VisADException
539             *             When bad things happen
540             * 
541             * @throws RemoteException
542             *             _more_
543             * @throws VisADException
544             *             _more_
545             */
546            public EarthLocation toEarth(DisplayEvent event) throws VisADException,
547                            RemoteException {
548                    NavigatedDisplay d = getNavigatedDisplay();
549                    return (d == null) ? null : d.getEarthLocation(toBox(event));
550            }
551    
552            /**
553             * _more_
554             * 
555             * @param el
556             *            _more_
557             */
558            public void addAODT(EarthLocation el) {
559                    final JDialog dialog = GuiUtils.createDialog("RUN AODT", true);
560                    String question = "Please select storm center";
561                    String label = "latitude: ";
562                    String label1 = "longitude: ";
563                    final JTextField field = new JTextField("", 10);
564                    final JTextField field1 = new JTextField("", 10);
565    
566                    ObjectListener listener = new ObjectListener(new Boolean(false)) {
567                            public void actionPerformed(ActionEvent ae) {
568                                    String cmd = ae.getActionCommand();
569                                    if ((ae.getSource() == field) || cmd.equals(GuiUtils.CMD_OK)) {
570                                            theObject = new Boolean(true);
571                                    } else {
572                                            theObject = new Boolean(false);
573                                    }
574                                    dialog.setVisible(false);
575                            }
576                    };
577                    ObjectListener listener1 = new ObjectListener(new Boolean(false)) {
578                            public void actionPerformed(ActionEvent ae) {
579                                    String cmd = ae.getActionCommand();
580                                    if ((ae.getSource() == field1) || cmd.equals(GuiUtils.CMD_OK)) {
581                                            theObject = new Boolean(true);
582                                    } else {
583                                            theObject = new Boolean(false);
584                                    }
585                                    dialog.setVisible(false);
586                            }
587                    };
588                    field.addActionListener(listener);
589                    field.addActionListener(listener1);
590                    List comps = new ArrayList();
591    
592                    comps.add(GuiUtils.left(GuiUtils.inset(new JLabel(question), 4)));
593    
594                    JPanel topb = GuiUtils.doLayout(new Component[] {
595                                    GuiUtils.rLabel(label),
596                                    GuiUtils.hbox(field, GuiUtils.filler()),
597                                    GuiUtils.rLabel(label1),
598                                    GuiUtils.hbox(field1, GuiUtils.filler()) }, 4,
599                                    GuiUtils.WT_NYNY, GuiUtils.WT_N);
600    
601                    comps.add(topb);
602    
603                    JComponent contents = GuiUtils.inset(GuiUtils.centerBottom(GuiUtils
604                                    .vbox(comps), GuiUtils.makeOkCancelButtons(listener1)), 4);
605    
606                    GuiUtils.packDialog(dialog, contents);
607                    Dimension ss = Toolkit.getDefaultToolkit().getScreenSize();
608    
609                    Point ctr = new Point(ss.width / 2 - 100, ss.height / 2 - 100);
610                    dialog.setLocation(ctr);
611                    dialog.setVisible(true);
612    
613            }
614    
615            /**
616             * Set the ProbeLocation property.
617             * 
618             * @param value
619             *            The new value for ProbeLocation
620             */
621            public void setProbeLocation(LatLonPoint value) {
622                    probeLocation = value;
623            }
624    
625            /**
626             * Get the ProbeLocation property.
627             * 
628             * @return The ProbeLocation
629             */
630            public LatLonPoint getProbeLocation() {
631                    return probeLocation;
632            }
633    
634            /**
635             * Set the RunOnClick property.
636             * 
637             * @param value
638             *            The new value for RunOnClick
639             */
640            public void setRunOnClick(boolean value) {
641                    this.runOnClick = value;
642            }
643    
644            /**
645             * Get the RunOnClick property.
646             * 
647             * @return The RunOnClick
648             */
649            public boolean getRunOnClick() {
650                    return this.runOnClick;
651            }
652    
653    }