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 }