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 }