001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 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 029package edu.wisc.ssec.mcidasv.control.cyclone; 030 031import java.awt.Component; 032import java.awt.Container; 033import java.awt.Dimension; 034import java.awt.Point; 035import java.awt.Toolkit; 036import java.awt.event.ActionEvent; 037import java.awt.event.ActionListener; 038import java.awt.event.InputEvent; 039import java.rmi.RemoteException; 040import java.util.ArrayList; 041import java.util.List; 042import java.util.Vector; 043 044import javax.swing.JButton; 045import javax.swing.JComboBox; 046import javax.swing.JComponent; 047import javax.swing.JDialog; 048import javax.swing.JEditorPane; 049import javax.swing.JLabel; 050import javax.swing.JPanel; 051import javax.swing.JScrollPane; 052import javax.swing.JTextField; 053 054import ucar.unidata.data.DataChoice; 055import ucar.unidata.data.DataInstance; 056import ucar.unidata.data.DataSourceImpl; 057import ucar.unidata.data.DataUtil; 058import ucar.unidata.data.grid.GridUtil; 059import ucar.unidata.data.imagery.AddeImageDataSource; 060import ucar.unidata.data.imagery.AddeImageDescriptor; 061import ucar.unidata.data.imagery.ImageDataSource; 062import ucar.unidata.idv.DisplayInfo; 063import ucar.unidata.idv.control.DisplayControlImpl; 064import ucar.unidata.ui.LatLonWidget; 065import ucar.unidata.util.GuiUtils; 066import ucar.unidata.util.Misc; 067import ucar.unidata.util.ObjectListener; 068import ucar.unidata.view.geoloc.NavigatedDisplay; 069import ucar.visad.Util; 070import ucar.visad.display.Animation; 071import ucar.visad.display.PointProbe; 072import ucar.visad.quantities.AirTemperature; 073import visad.CommonUnit; 074import visad.DateTime; 075import visad.DisplayEvent; 076import visad.FieldImpl; 077import visad.FlatField; 078import visad.Real; 079import visad.RealTuple; 080import visad.RealTupleType; 081import visad.Set; 082import visad.VisADException; 083import visad.georef.EarthLocation; 084import visad.georef.LatLonPoint; 085import visad.util.DataUtility; 086import edu.wisc.ssec.mcidas.AreaDirectory; 087import edu.wisc.ssec.mcidasv.data.cyclone.StormAODT; 088import edu.wisc.ssec.mcidasv.data.cyclone.StormAODTInfo; 089import 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 096public 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}