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 }