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