001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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 https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.adde; 030 031import java.awt.Component; 032import java.awt.Container; 033import java.awt.Dimension; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.io.File; 037import java.io.RandomAccessFile; 038import java.rmi.RemoteException; 039import java.text.SimpleDateFormat; 040import java.util.ArrayList; 041import java.util.Arrays; 042import java.util.Collection; 043import java.util.Collections; 044import java.util.Date; 045import java.util.Enumeration; 046import java.util.HashMap; 047import java.util.Hashtable; 048import java.util.Iterator; 049import java.util.List; 050import java.util.Map; 051import java.util.StringTokenizer; 052import java.util.TimeZone; 053import java.util.TreeMap; 054 055import javax.swing.BoxLayout; 056import javax.swing.JCheckBox; 057import javax.swing.JComponent; 058import javax.swing.JLabel; 059import javax.swing.JOptionPane; 060import javax.swing.JPanel; 061import javax.swing.JScrollPane; 062import javax.swing.JTabbedPane; 063 064import edu.wisc.ssec.mcidasv.Constants; 065import org.slf4j.Logger; 066import org.slf4j.LoggerFactory; 067 068import edu.wisc.ssec.mcidas.AREAnav; 069import edu.wisc.ssec.mcidas.AreaDirectory; 070import edu.wisc.ssec.mcidas.AreaDirectoryList; 071import edu.wisc.ssec.mcidas.AreaFile; 072import edu.wisc.ssec.mcidas.AreaFileException; 073import edu.wisc.ssec.mcidas.adde.AddeImageURL; 074import edu.wisc.ssec.mcidas.adde.AddeTextReader; 075import edu.wisc.ssec.mcidas.adde.AddeURL; 076import edu.wisc.ssec.mcidasv.data.GeoLatLonSelection; 077import edu.wisc.ssec.mcidasv.data.GeoPreviewSelection; 078 079import visad.CommonUnit; 080import visad.Data; 081import visad.DateTime; 082import visad.DisplayRenderer; 083import visad.FlatField; 084import visad.FunctionType; 085import visad.MathType; 086import visad.RealType; 087import visad.Set; 088import visad.VisADException; 089import visad.data.DataRange; 090import visad.data.mcidas.AREACoordinateSystem; 091import visad.data.mcidas.AreaAdapter; 092import visad.georef.MapProjection; 093import visad.meteorology.ImageSequence; 094import visad.meteorology.ImageSequenceImpl; 095import visad.meteorology.SingleBandedImage; 096 097import ucar.unidata.data.BadDataException; 098import ucar.unidata.data.CompositeDataChoice; 099import ucar.unidata.data.DataCategory; 100import ucar.unidata.data.DataChoice; 101import ucar.unidata.data.DataSelection; 102import ucar.unidata.data.DataSelectionComponent; 103import ucar.unidata.data.DataSourceDescriptor; 104import ucar.unidata.data.DerivedDataChoice; 105import ucar.unidata.data.DirectDataChoice; 106import ucar.unidata.data.GeoLocationInfo; 107import ucar.unidata.data.GeoSelection; 108import ucar.unidata.data.imagery.AddeImageDataSource; 109import ucar.unidata.data.imagery.AddeImageDescriptor; 110import ucar.unidata.data.imagery.AddeImageInfo; 111import ucar.unidata.data.imagery.BandInfo; 112import ucar.unidata.data.imagery.ImageDataset; 113import ucar.unidata.geoloc.LatLonPoint; 114import ucar.unidata.idv.DisplayControl; 115import ucar.unidata.idv.MapViewManager; 116import ucar.unidata.idv.ViewManager; 117import ucar.unidata.util.GuiUtils; 118import ucar.unidata.util.IOUtil; 119import ucar.unidata.util.LogUtil; 120import ucar.unidata.util.PollingInfo; 121import ucar.unidata.util.StringUtil; 122import ucar.unidata.util.ThreeDSize; 123import ucar.unidata.util.TwoFacedObject; 124import ucar.visad.UtcDate; 125import ucar.visad.Util; 126import ucar.visad.data.AreaImageFlatField; 127 128/** 129 * Abstract DataSource class for images files. 130 */ 131 132public class AddeImageParameterDataSource extends AddeImageDataSource { 133 134 private static final Logger logger = LoggerFactory.getLogger(AddeImageParameterDataSource.class); 135 136 /** 137 * Public keys for server, group, dataset, user, project. 138 */ 139 public final static String SIZE_KEY = "size"; 140 public final static String PLACE_KEY = "place"; 141 public final static String LATLON_KEY = "latlon"; 142 public final static String LINELE_KEY = "linele"; 143 public final static String MAG_KEY = "mag"; 144 public final static String BAND_KEY = "band"; 145 public final static String BANDINFO_KEY = "bandinfo"; 146 public final static String UNIT_KEY = "unit"; 147 public final static String PREVIEW_KEY = "preview"; 148 public final static String SPAC_KEY = "spac"; 149 public final static String NAV_KEY = "nav"; 150 public final static String AUX_KEY = "aux"; 151 public final static String DOC_KEY = "doc"; 152 public final static String SPACING_BRIT = "1"; 153 public final static String SPACING_NON_BRIT = "4"; 154 155 /** The first projection we find */ 156// protected ProjectionImpl sampleProjection; 157 public MapProjection sampleMapProjection; 158 159 /* ADDE request string */ 160 private String source; 161 private String baseSource; 162 163 /* properties for this data source */ 164 private Hashtable sourceProps; 165 private Hashtable selectionProps; 166 167 private int lineResolution; 168 private int elementResolution; 169 private float lRes; 170 private float eRes; 171 private int lineMag = 1; 172 private int elementMag = 1; 173 174 private GeoSelection lastGeoSelection; 175 private DataChoice lastChoice = null; 176 private Boolean showPreview = Boolean.FALSE; 177 private FlatField previewImage = null; 178 private MapProjection previewProjection; 179 private Hashtable initProps; 180 181 private AreaDirectory previewDir = null; 182 private AREAnav previewNav = null; 183 private boolean haveDataSelectionComponents = false; 184 185 private GeoPreviewSelection previewSel; 186 private GeoLatLonSelection laLoSel; 187 188 private String choiceName; 189 190 private String saveCoordType; 191 private String savePlace; 192 private double saveLat; 193 private double saveLon; 194 private int saveNumLine; 195 private int saveNumEle; 196 private int saveLineMag; 197 private int saveEleMag; 198 private Boolean saveShowPreview; 199 200 private String displaySource; 201 202 // keep track of extra info for derived fields, since they may be a mix of bands and resolutions 203 boolean isDerived = false; 204 HashMap<Integer, Double> derivedBandLineRes = new HashMap<Integer, Double>(); 205 HashMap<Integer, Double> derivedBandElemRes = new HashMap<Integer, Double>(); 206 HashMap<Integer, Integer> derivedBandMagFactor = new HashMap<Integer, Integer>(); 207 208 protected List<DataChoice> stashedChoices = null; 209 private List iml = new ArrayList(); 210 private List saveImageList = new ArrayList(); 211 212 private int previewLineRes = 1; 213 private int previewEleRes = 1; 214 215 // Do binary search on preview bounds for GEO sensors to speed up overall response time 216 boolean isGeoSensor = false; 217 218 // Also need to know when dealing with a sensor where sectors shift around spatially 219 boolean isABISensor = false; 220 221 /** Whether or not this DataSource was loaded from a bundle. */ 222 private boolean fromBundle = false; 223 224 /** Are any of the data choices based upon remote files? */ 225 private boolean hasRemoteChoices = false; 226 227 private Map<String, AreaDirectory> requestIdToDirectory = new HashMap<String, AreaDirectory>(); 228 229 // TJJ Aug 2020 230 // Detect domain shift - for ex ABI MESOs can abruptly move 231 // If we detect one, load the later, shifted image(s) earth-centered relative to the earlier 232 boolean domainShiftDetected = false; 233 boolean domainShiftNoticeDerivedShown = false; 234 boolean domainShiftNoticeTargetShown = false; 235 236 public AddeImageParameterDataSource() {} 237 238 /** 239 * Creates a {@code AddeImageParameterDataSource} with a single ADDE URL. 240 * <b>Note:</b> the URLs should point at {@literal "image"} data. 241 * 242 * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source. 243 * @param image ADDE URL 244 * @param properties The properties for this data source. 245 * 246 * @throws VisADException 247 */ 248 public AddeImageParameterDataSource(DataSourceDescriptor descriptor, String image, 249 Hashtable properties) 250 throws VisADException { 251 super(descriptor, new String[] { image }, properties); 252 logger.trace("1: desc={}, image={}, properties={}", new Object[] { descriptor, image, properties }); 253 } 254 255 /** 256 * Create a new AddeImageParameterDataSource with an array of ADDE URL strings. 257 * <b>Note:</b> the URLs should point at {@literal "image"} data. 258 * 259 * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source. 260 * @param images Array of ADDE URLs. 261 * @param properties Properties for this data source. 262 * 263 * @throws VisADException 264 */ 265 public AddeImageParameterDataSource(DataSourceDescriptor descriptor, String[] images, 266 Hashtable properties) throws VisADException { 267 super(descriptor, images, properties); 268 logger.trace("2: desc={}, images={}, properties={}", new Object[] { descriptor, images, properties }); 269 } 270 271 /** 272 * Creates a new {@code AddeImageParameterDataSource} with an 273 * {@link java.util.List List} of ADDE URL strings. 274 * <b>Note:</b> the URLs should point at {@literal "image"} data. 275 * 276 * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source. 277 * @param images {@code List} of ADDE URL strings. 278 * @param properties Properties for this data source. 279 * 280 * @throws VisADException 281 */ 282 public AddeImageParameterDataSource(DataSourceDescriptor descriptor, List images, 283 Hashtable properties) throws VisADException { 284 super(descriptor, images, properties); 285 logger.trace("3: desc={}, images={}, properties={}", new Object[] { descriptor, images, properties }); 286 } 287 288 /** 289 * Create a new AddeImageParameterDataSource with the given dataset. 290 * 291 * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source. 292 * @param ids Dataset. 293 * @param properties Properties for this data source. 294 * 295 * @throws VisADException 296 */ 297 298 public AddeImageParameterDataSource(DataSourceDescriptor descriptor, ImageDataset ids, 299 Hashtable properties) throws VisADException { 300 super(descriptor, ids, properties); 301 logger.trace("4: desc={}, ids={}, properties={}", new Object[] { descriptor, ids, properties }); 302 this.sourceProps = properties; 303 if (properties.containsKey((Object)PREVIEW_KEY)) { 304 this.showPreview = (Boolean)(properties.get((Object)PREVIEW_KEY)); 305 saveShowPreview = showPreview; 306 } else { 307 if (saveShowPreview != null) { 308 showPreview = saveShowPreview; 309 } 310 } 311 312 List descs = ids.getImageDescriptors(); 313 AddeImageDescriptor aid = (AddeImageDescriptor)descs.get(0); 314 this.source = aid.getSource(); 315 if (this.source.contains("localhost")) { 316 AreaDirectory areaDirectory = aid.getDirectory(); 317 if (!sourceProps.containsKey((Object)UNIT_KEY)) { 318 if (!sourceProps.containsKey((Object)BAND_KEY)) { 319 String calType = areaDirectory.getCalibrationType(); 320 if (!calType.equals("RAW")) { 321 sourceProps.put(UNIT_KEY, calType); 322 int[] bandNums = areaDirectory.getBands(); 323 String bandString = Integer.valueOf(bandNums[0]).toString(); 324 sourceProps.put(BAND_KEY, bandString); 325 } 326 } 327 } 328 } 329 setMag(); 330 getAreaDirectory(properties); 331 } 332 333 @Override protected void propertiesChanged() { 334 logger.trace("fired"); 335 super.propertiesChanged(); 336 } 337 338 @Override protected boolean initDataFromPollingInfo() { 339 boolean result = super.initDataFromPollingInfo(); 340 logger.trace("result={}", result); 341 return result; 342 } 343 344 @Override protected boolean isPolling() { 345 boolean result = super.isPolling(); 346 logger.trace("isPolling={}", result); 347 return result; 348 } 349 350 @Override public void setPollingInfo(PollingInfo value) { 351 logger.trace("value={}", value); 352 super.setPollingInfo(value); 353 } 354 355 @Override protected boolean hasPollingInfo() { 356 boolean result = super.hasPollingInfo(); 357 logger.trace("hasPollingInfo={}", result); 358 return result; 359 } 360 361 @Override public PollingInfo getPollingInfo() { 362 PollingInfo result = super.getPollingInfo(); 363 logger.trace("getPollingInfo={}", result); 364 return result; 365 } 366 367 @Override public void initAfterUnpersistence() { 368 logger.trace("unbundled!"); 369 super.initAfterUnpersistence(); 370 371 if (this.sourceProps.containsKey(PREVIEW_KEY)) { 372 this.showPreview = (Boolean)this.sourceProps.get(PREVIEW_KEY); 373 if (this.showPreview == null) { 374 this.showPreview = Boolean.FALSE; 375 } 376 this.saveShowPreview = this.showPreview; 377 } 378 379 fromBundle = true; 380 List<AddeImageDescriptor> descriptors = (List<AddeImageDescriptor>) getImageList(); 381 this.source = descriptors.get(0).getSource(); // TODO: why not use the source from 382 // each AddeImageDescriptor? 383 384 boolean isRelative = false; 385 for (AddeImageDescriptor descriptor : descriptors) { 386 if (descriptor.getIsRelative()) isRelative = true; 387 if (!isFromFile(descriptor)) { 388 this.hasRemoteChoices = true; 389 break; 390 } 391 } 392 393 // For bundles with relative times, turn wireframe box off, it may be inaccurate at this point in time. 394 logger.debug("isRelative: " + isRelative); 395 ViewManager vm = getIdv().getVMManager().getLastActiveViewManager(); 396 if (vm instanceof MapViewManager && isRelative) { 397 DisplayRenderer renderer = vm.getDisplayRenderer(); 398 try { 399 renderer.setBoxOn(false); 400 } catch (RemoteException e) { 401 throw new RuntimeException(e); 402 } catch (VisADException e) { 403 throw new RuntimeException(e); 404 } 405 } 406 } 407 408 @Override public boolean canSaveDataToLocalDisk() { 409 return true; 410 } 411 412 private Hashtable<String, DataSelection> choiceToSel = new Hashtable<String, DataSelection>(); 413 414 public DataSelection getSelForChoice(final DataChoice choice) { 415 String key = choice.getName(); 416 return choiceToSel.get(key); 417 } 418 public boolean hasSelForChoice(final DataChoice choice) { 419 String key = choice.getName(); 420 return choiceToSel.containsKey(key); 421 } 422 public void putSelForChoice(final DataChoice choice, final DataSelection sel) { 423 String key = choice.getName(); 424 choiceToSel.put(key, sel); 425 } 426 427 /** 428 * Save files to local disk 429 * 430 * @param prefix destination dir and file prefix 431 * @param loadId For JobManager 432 * @param changeLinks Change internal file references 433 * 434 * @return Files copied 435 * 436 * @throws Exception On badness 437 */ 438 439 @Override protected List saveDataToLocalDisk(String prefix, Object loadId, boolean changeLinks) throws Exception { 440 logger.trace("prefix={} loadId={} changeLinks={}", new Object[] { prefix, loadId, changeLinks }); 441 final List<JCheckBox> checkboxes = new ArrayList<JCheckBox>(); 442 List categories = new ArrayList(); 443 Hashtable catMap = new Hashtable(); 444 Hashtable currentDataChoices = new Hashtable(); 445 446 List displays = getIdv().getDisplayControls(); 447 for (int i = 0; i < displays.size(); i++) { 448 List dataChoices = ((DisplayControl)displays.get(i)).getDataChoices(); 449 if (dataChoices == null) { 450 continue; 451 } 452 List finalOnes = new ArrayList(); 453 for (int j = 0; j < dataChoices.size(); j++) { 454 ((DataChoice)dataChoices.get(j)).getFinalDataChoices(finalOnes); 455 } 456 for (int dcIdx = 0; dcIdx < finalOnes.size(); dcIdx++) { 457 DataChoice dc = (DataChoice)finalOnes.get(dcIdx); 458 if (!(dc instanceof DirectDataChoice)) { 459 continue; 460 } 461 DirectDataChoice ddc = (DirectDataChoice) dc; 462 if (ddc.getDataSource() != this) { 463 continue; 464 } 465 currentDataChoices.put(ddc.getName(), ""); 466 } 467 } 468 469 for (int i = 0; i < dataChoices.size(); i++) { 470 DataChoice dataChoice = (DataChoice) dataChoices.get(i); 471 if (!(dataChoice instanceof DirectDataChoice)) { 472 continue; 473 } 474 475 // skip over datachoices that the user has not already loaded. 476 // (but fill the "slot" with null (it's a hack to signify that 477 // the "download" loop should skip over the data choice associated 478 // with this slot) 479 if (!currentDataChoices.containsKey(dataChoice.getName())) { 480 checkboxes.add(null); // 481 continue; 482 } 483 484 String label = dataChoice.getDescription(); 485 if (label.length() > 30) { 486 label = label.substring(0, 29) + "..."; 487 } 488 JCheckBox cbx = 489 new JCheckBox(label, 490 currentDataChoices.get(dataChoice.getName()) 491 != null); 492 ThreeDSize size = (ThreeDSize)dataChoice.getProperty(SIZE_KEY); 493 cbx.setToolTipText(dataChoice.getName()); 494 checkboxes.add(cbx); 495 DataCategory dc = dataChoice.getDisplayCategory(); 496 if (dc == null) { 497 dc = DataCategory.createCategory(DataCategory.CATEGORY_IMAGE); 498 } 499 List comps = (List)catMap.get(dc); 500 if (comps == null) { 501 comps = new ArrayList(); 502 catMap.put(dc, comps); 503 categories.add(dc); 504 } 505 comps.add(cbx); 506 comps.add(GuiUtils.filler()); 507 if (size != null) { 508 JLabel sizeLabel = GuiUtils.rLabel(size.getSize() + " "); 509 sizeLabel.setToolTipText(size.getLabel()); 510 comps.add(sizeLabel); 511 } else { 512 comps.add(new JLabel("")); 513 } 514 } 515 final JCheckBox allCbx = new JCheckBox("Select All"); 516 allCbx.addActionListener(new ActionListener() { 517 public void actionPerformed(ActionEvent ae) { 518 for (JCheckBox cbx : checkboxes) { 519 if (cbx != null) { 520 cbx.setSelected(allCbx.isSelected()); 521 } 522 } 523 } 524 }); 525 526 JTabbedPane tab = new JTabbedPane(JTabbedPane.LEFT); 527 528 for (int i = 0; i < categories.size(); i++) { 529 List comps = (List) catMap.get(categories.get(i)); 530 JPanel innerPanel = GuiUtils.doLayout(comps, 3, GuiUtils.WT_NYN, GuiUtils.WT_N); 531 JScrollPane sp = new JScrollPane(GuiUtils.top(innerPanel)); 532 sp.setPreferredSize(new Dimension(500, 400)); 533 JPanel top = GuiUtils.right(GuiUtils.rLabel(" ")); 534 JComponent inner = GuiUtils.inset(GuiUtils.topCenter(top, sp), 5); 535 tab.addTab(categories.get(i).toString(), inner); 536 } 537 538 JComponent contents = tab; 539 contents = GuiUtils.topCenter( 540 GuiUtils.inset( 541 GuiUtils.leftRight( 542 new JLabel("Select the fields to download"), 543 allCbx), 5), contents); 544 JLabel label = new JLabel(getNameForDataSource(this, 50, true)); 545 contents = GuiUtils.topCenter(label, contents); 546 contents = GuiUtils.inset(contents, 5); 547 if (!GuiUtils.showOkCancelDialog(null, "", contents, null)) { 548 return null; 549 } 550 551 // iterate through user's selection to build list of things to download 552 List<String> realUrls = new ArrayList<String>(); 553 List<AddeImageDescriptor> descriptorsToSave = new ArrayList<AddeImageDescriptor>(); 554 List<BandInfo> bandInfos = (List<BandInfo>)getProperty(PROP_BANDINFO, (Object)null); 555 List<BandInfo> savedBands = new ArrayList<BandInfo>(); 556 for (int i = 0; i < dataChoices.size(); i++) { 557 DataChoice dataChoice = (DataChoice)dataChoices.get(i); 558 if (!(dataChoice instanceof DirectDataChoice)) { 559 continue; 560 } 561 JCheckBox cbx = (JCheckBox)checkboxes.get(i); 562 if (cbx == null || !cbx.isSelected()) { 563 continue; 564 } 565 566 if (dataChoice.getDataSelection() == null) { 567 dataChoice.setDataSelection(getSelForChoice(dataChoice)); 568 } 569 logger.trace("selected choice={} id={}", dataChoice.getName(), dataChoice.getId()); 570 List<AddeImageDescriptor> descriptors = getDescriptors(dataChoice, dataChoice.getDataSelection()); 571 logger.trace("descriptors={}", descriptors); 572 573 BandInfo bandInfo; 574 Object dataChoiceId = dataChoice.getId(); 575 if (dataChoiceId instanceof BandInfo) { 576 bandInfo = (BandInfo)dataChoiceId; 577 } else { 578 bandInfo = bandInfos.get(0); 579 } 580 String preferredUnit = bandInfo.getPreferredUnit(); 581 List<TwoFacedObject> filteredCalUnits = new ArrayList<TwoFacedObject>(); 582 for (TwoFacedObject tfo : (List<TwoFacedObject>)bandInfo.getCalibrationUnits()) { 583 if (preferredUnit.equals(tfo.getId())) { 584 filteredCalUnits.add(tfo); 585 } 586 } 587 bandInfo.setCalibrationUnits(filteredCalUnits); 588 savedBands.add(bandInfo); 589 590 DataSelection selection = dataChoice.getDataSelection(); 591 if (selection == null) { 592 if (getSelForChoice(dataChoice) != null) { 593 selection = getSelForChoice(dataChoice); 594 } else { 595 selection = getDataSelection(); 596 } 597 } 598 599 Hashtable selectionProperties = selection.getProperties(); 600// Hashtable selectionProperties; 601// if (selection != null) { 602// selectionProperties = selection.getProperties(); 603// } else { 604// DataSelection sel = this.getDataSelection(); 605// selectionProperties = new Hashtable(); 606// } 607 logger.trace("bandinfo.getUnit={} selection props={}", bandInfo.getPreferredUnit(), selectionProperties); 608 for (AddeImageDescriptor descriptor : descriptors) { 609// AddeImageInfo aii = (AddeImageInfo)descriptor.getImageInfo().clone(); 610 if (!isFromFile(descriptor)) { 611 String src = descriptor.getSource(); 612 logger.trace("src before={}", src); 613 src = replaceKey(src, AddeImageURL.KEY_UNIT, bandInfo.getPreferredUnit()); 614 if (selectionProperties.containsKey(AddeImageURL.KEY_PLACE)) { 615 src = replaceKey(src, AddeImageURL.KEY_PLACE, selectionProperties.get(AddeImageURL.KEY_PLACE)); 616 } 617 if (selectionProperties.containsKey(AddeImageURL.KEY_LATLON)) { 618 src = replaceKey(src, AddeImageURL.KEY_LINEELE, AddeImageURL.KEY_LATLON, selectionProperties.get(AddeImageURL.KEY_LATLON)); 619 } 620 if (selectionProperties.containsKey(AddeImageURL.KEY_LINEELE)) { 621 src = removeKey(src, AddeImageURL.KEY_LATLON); 622 src = replaceKey(src, AddeImageURL.KEY_LINEELE, selectionProperties.get(AddeImageURL.KEY_LINEELE)); 623 } 624 if (selectionProperties.containsKey(AddeImageURL.KEY_MAG)) { 625 src = replaceKey(src, AddeImageURL.KEY_MAG, selectionProperties.get(AddeImageURL.KEY_MAG)); 626 } 627 if (selectionProperties.containsKey(AddeImageURL.KEY_SIZE)) { 628 src = replaceKey(src, AddeImageURL.KEY_SIZE, selectionProperties.get(AddeImageURL.KEY_SIZE)); 629 } 630 logger.trace("src after={}", src); 631 descriptor.setSource(src); 632 } 633 descriptorsToSave.add(descriptor); 634 } 635// descriptorsToSave.addAll(descriptors); 636 } 637 if (!savedBands.isEmpty()) { 638 setProperty(PROP_BANDINFO, savedBands); 639 } 640 if (descriptorsToSave.isEmpty()) { 641 return null; 642 } 643 644 // Start the load, showing the dialog 645 List<String> suffixes = new ArrayList<String>(); 646 SimpleDateFormat sdf = new SimpleDateFormat("_" + DATAPATH_DATE_FORMAT); 647 sdf.setTimeZone(TimeZone.getTimeZone("GMT")); 648 for (int i = 0; i < descriptorsToSave.size(); i++) { 649 AddeImageDescriptor descriptor = descriptorsToSave.get(i); 650 AddeImageInfo aii = descriptor.getImageInfo(); 651 DateTime dttm = (DateTime)timeMap.get(descriptor.getSource()); 652 if (dttm != null) { 653 suffixes.add(sdf.format(ucar.visad.Util.makeDate(dttm)) + ".area"); 654 } else if (aii != null) { 655 String suffix = "_Band"+aii.getBand()+"_Unit"+aii.getUnit()+"_Pos"+i+".area"; 656 suffixes.add(suffix); 657 logger.trace("test suffix={}", suffix); 658 } else { 659 suffixes.add(i + ".area"); 660 } 661 realUrls.add(descriptor.getSource()); 662 } 663 logger.trace("urls={}", realUrls); 664 logger.trace("prefix={}", prefix); 665 logger.trace("suffixes={}", suffixes); 666 logger.trace("loadId={}", loadId); 667 List newFiles = IOUtil.writeTo(realUrls, prefix, suffixes, loadId); 668 logger.trace("files={}", newFiles); 669 if (newFiles == null) { 670 logger.trace("failed while in writeTo?"); 671 return null; 672 } else { 673 logger.trace("finished writeTo!"); 674 } 675 if (changeLinks) { 676 imageList = newFiles; 677 } 678 679 // write 0 as the first word 680 for (int i = 0; i < newFiles.size(); i++) { 681 try { 682 RandomAccessFile to = new RandomAccessFile((String)newFiles.get(i), "rw"); 683 to.seek(0); 684 to.writeInt(0); 685 to.close(); 686 } catch (Exception e) { 687 logger.error("unable to set first word to zero", e); 688 } 689 } 690 691 692// if (geoSubset != null) { 693// geoSubset.clearStride(); 694// geoSubset.setBoundingBox(null); 695// if (geoSelectionPanel != null) { 696// geoSelectionPanel.initWith(doMakeGeoSelectionPanel()); 697// } 698// } 699 700// List newFiles = Misc.newList(path); 701// if (changeLinks) { 702// //Get rid of the resolver URL 703// getProperties().remove(PROP_RESOLVERURL); 704// setNewFiles(newFiles); 705// } 706// 707 logger.trace("returning={}", newFiles); 708 return newFiles; 709 } 710 711 @Override protected String getDataPrefix() { 712 String tmp = StringUtil.replace(getName(), ' ', ""); 713 tmp = StringUtil.replace(tmp, '/', ""); 714 tmp = StringUtil.replace(tmp, "(AllBands)", ""); 715 tmp = IOUtil.cleanFileName(tmp); 716 logger.trace("data prefix={}", tmp); 717 return tmp; 718 } 719 720 /** 721 * A utility method that helps us deal with legacy bundles that used to 722 * have String file names as the id of a data choice. 723 * 724 * @param object May be an AddeImageDescriptor (for new bundles) or a 725 * String that is converted to an image descriptor. 726 * @return The image descriptor. 727 */ 728 @Override public AddeImageDescriptor getDescriptor(Object object) { 729// logger.trace("--------------------"); 730 if (object == null) { 731// logger.trace("null obj"); 732 return null; 733 } 734 if (object instanceof DataChoice) { 735 object = ((DataChoice)object).getId(); 736 logger.trace("datachoice getId={}", object); 737 } 738 if (object instanceof ImageDataInfo) { 739 int index = ((ImageDataInfo) object).getIndex(); 740 if (index < myDataChoices.size()) { 741 DataChoice dc = (DataChoice)myDataChoices.get(index); 742 Object tmpObject = dc.getId(); 743 if (tmpObject instanceof ImageDataInfo) { 744// logger.trace("returning imagedatainfo"); 745 return ((ImageDataInfo)tmpObject).getAid(); 746 } 747 } 748// logger.trace("invalid idx for imagedatainfo? (idx={} vs size={})", index, myDataChoices.size()); 749 return null; 750 // return ((ImageDataInfo) object).getAid(); 751 } 752 753 if (object instanceof AddeImageDescriptor) { 754// logger.trace("already addeimagedesc! desc={}", object); 755 return (AddeImageDescriptor)object; 756 } 757 AddeImageDescriptor tmp = new AddeImageDescriptor(object.toString()); 758// logger.trace("return descriptor={}", tmp); 759// logger.trace("--------------------"); 760 return tmp; 761 } 762 763 /** 764 * Overwrite base class method to return the name of this class. 765 * 766 * @return The name. 767 */ 768 public String getImageDataSourceName() { 769 return "Adde Image Data Source (Parameter)"; 770 } 771 772 private void setMag() { 773 Object magKey = (Object)"mag"; 774 if (sourceProps.containsKey(magKey)) { 775 String magVal = (String)(sourceProps.get(magKey)); 776 String[] magVals = magVal.split(" "); 777 this.lineMag = Integer.parseInt(magVals[0]); 778 this.elementMag = Integer.parseInt(magVals[1]); 779 } 780 } 781 782 private void getAreaDirectory(Hashtable properties) { 783 String addeCmdBuff = source; 784 if (addeCmdBuff.contains("BAND=")) { 785 String bandStr = getKey(addeCmdBuff, "BAND"); 786 if (bandStr.length() == 0) { 787 addeCmdBuff = replaceKey(addeCmdBuff, "BAND", "1"); 788 } 789 } 790 if (addeCmdBuff.contains("MAG=")) { 791 String[] segs = addeCmdBuff.split("MAG="); 792 String seg0 = segs[0]; 793 String seg1 = segs[1]; 794 int indx = seg1.indexOf("&"); 795 seg1 = seg1.substring(indx); 796 String magString = lineMag + " " + elementMag; 797 addeCmdBuff = seg0 + "MAG=" + magString + seg1; 798 } 799 addeCmdBuff = addeCmdBuff.replace("imagedata", "imagedir"); 800 AreaDirectoryList dirList = null; 801 try { 802 dirList = new AreaDirectoryList(addeCmdBuff); 803 } catch (Exception e) { 804 try { 805 List<BandInfo> bandInfos = (List<BandInfo>)getProperty(PROP_BANDINFO, (Object)null); 806 BandInfo bi = bandInfos.get(0); 807// String bandStr = Integer.valueOf(bi.getBandNumber()).toString(); 808 addeCmdBuff = replaceKey(addeCmdBuff, "BAND", bi.getBandNumber()); 809 dirList = new AreaDirectoryList(addeCmdBuff); 810 } catch (Exception eOpen) { 811 setInError(true); 812 logger.error("problem opening AREA file", eOpen); 813 } 814 } 815 816 try { 817 List areaDirs = dirList.getDirs(); 818 AreaDirectory ad = (AreaDirectory)areaDirs.get(0); 819 float[] res = getLineEleResolution(ad); 820 float resol = res[0]; 821 if (this.lineMag < 0) { 822 resol *= Math.abs(this.lineMag); 823 } 824// this.lineResolution = ad.getValue(11); 825 this.lineResolution = ad.getValue(AreaFile.AD_LINERES); 826 this.lRes = resol; 827 resol = res[1]; 828 if (this.elementMag < 0) { 829 resol *= Math.abs(this.elementMag); 830 } 831// this.elementResolution = ad.getValue(12); 832 this.elementResolution = ad.getValue(AreaFile.AD_ELEMRES); 833 this.eRes = resol; 834 } catch (Exception e) { 835 setInError(true); 836 logger.error("getting area directory", e); 837 } 838 baseSource = addeCmdBuff; 839 } 840 841 protected void initDataSelectionComponents( 842 List components, final DataChoice dataChoice) 843 { 844 if (fromBundle && !hasRemoteChoices) { 845 components.add(new BundlePreviewSelection("Region (Disabled)")); 846 components.add(new BundlePreviewSelection("Advanced (Disabled)")); 847 return; 848 } 849 850 getIdv().showWaitCursor(); 851 852 boolean hasImagePreview = true; 853 if (this.showPreview == null) { 854 this.showPreview = true; 855 } 856 boolean basically = false; 857 if (this.lastChoice != null) { 858 basically = dataChoice.basicallyEquals(this.lastChoice); 859 } 860 logger.trace("dataChoice={}", dataChoice); 861 // check for comps and whether or not dataChoice is hooping right back into line 862 if (this.haveDataSelectionComponents && dataChoice.equals(this.lastChoice)) { 863 try { 864 // did the datachoice ever actually get data? 865 if (dataChoice.getDataSelection() == null) { 866 if (!basically) { 867 logger.trace("creating geolatlonselection"); 868 this.laLoSel = new GeoLatLonSelection(this, 869 dataChoice, this.initProps, this.previewProjection, 870 previewDir, previewNav); 871 872 this.lineMag = this.laLoSel.getLineMag(); 873 this.elementMag = this.laLoSel.getElementMag(); 874 875 /* DAVEP: Force preview on. "No preview" means blank image */ 876// this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 877// this.laLoSel, this.previewProjection, 878// this.lineMag, this.elementMag, this.showPreview); 879 logger.trace("1: creating geopreviewselection: has geoprevsel: {}", this.previewSel!=null); 880 this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 881 this.laLoSel, this.previewProjection, 882 this.lineMag, this.elementMag, true); 883 } 884// this.lineMag = this.laLoSel.getLineMag(); 885// this.elementMag = this.laLoSel.getElementMag(); 886// 887// /* DAVEP: Force preview on. "No preview" means blank image */ 888//// this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 889//// this.laLoSel, this.previewProjection, 890//// this.lineMag, this.elementMag, this.showPreview); 891// logger.trace("1: creating geopreviewselection: has geoprevsel: {}", this.previewSel!=null); 892// this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 893// this.laLoSel, this.previewProjection, 894// this.lineMag, this.elementMag, true); 895 } 896 components.add(this.previewSel); 897 components.add(this.laLoSel); 898 } catch (Exception e) { 899 logger.error("error while repeating addition of selection components", e); 900 getIdv().showNormalCursor(); 901 } 902 } else { 903 try { 904 hasImagePreview = makePreviewImage(dataChoice); 905 if (basically) { 906 getSaveComponents(); 907 } 908 } catch (Exception e) { 909 logger.error("Preview image Exception: " + e.getMessage()); 910 JLabel label = new JLabel("Can't make preview image"); 911 JPanel contents = GuiUtils.top(GuiUtils.inset(label, label.getText().length() + 12)); 912 GuiUtils.showOkDialog(null, "No Preview Image", contents, null); 913 getIdv().showNormalCursor(); 914 logger.error("problem creating preview image", e); 915 return; 916 } 917 this.lastChoice = dataChoice; 918 if (hasImagePreview) { 919 try { 920 String magStr = getKey(baseSource, MAG_KEY); 921 String saveMagStr = magStr; 922 String[] vals = StringUtil.split(magStr, " ", 2); 923 Integer iVal = Integer.valueOf(vals[0]); 924 int lMag = iVal.intValue() * -1; 925 if (lMag == -1) { 926 lMag = 1; 927 } 928 iVal = Integer.valueOf(vals[1]); 929 int eMag = iVal.intValue() * -1; 930 if (eMag == -1) { 931 eMag = 1; 932 } 933 magStr = lMag + " " + eMag; 934 replaceKey(MAG_KEY, magStr); 935// String saveStr = baseSource; 936// if (!showPreview) { 937// replaceKey(SIZE_KEY, "2 2"); 938// } 939 AreaAdapter aa = null; 940 AREACoordinateSystem acs = null; 941 try { 942 logger.trace("creating AreaFile from src={}", baseSource); 943 if (showPreview) { 944 aa = new AreaAdapter(baseSource, false); 945 this.previewImage = (FlatField)aa.getImage(); 946 } else { 947 this.previewImage = Util.makeField(0, 1, 1, 0, 1, 1, 0, "TEMP"); 948 } 949 950 AreaFile af = new AreaFile(baseSource); 951 previewNav = af.getNavigation(); 952 AreaDirectory ad = af.getAreaDirectory(); 953 this.lineResolution = ad.getValue(AreaFile.AD_LINERES); 954 this.elementResolution = ad.getValue(AreaFile.AD_ELEMRES); 955 acs = new AREACoordinateSystem(af); 956 } catch (Exception e) { 957 String excp = e.toString(); 958 int indx = excp.lastIndexOf(":"); 959 String errorText = excp.substring(indx+1); 960 JLabel label = new JLabel(errorText); 961 JPanel contents = GuiUtils.top(GuiUtils.inset(label, label.getText().length() + 12)); 962 GuiUtils.showOkDialog(null, "Can't Make Geographical Selection Tabs", contents, null); 963 getIdv().showNormalCursor(); 964 logger.error("problem creating preview image", e); 965 return; 966 } 967 this.initProps = new Hashtable(); 968 Enumeration propEnum = sourceProps.keys(); 969 for (int i = 0; propEnum.hasMoreElements(); i++) { 970 String key = propEnum.nextElement().toString(); 971 Object val = sourceProps.get(key); 972 key = key.toUpperCase(); 973 if (val instanceof String) { 974 String str = (String)val; 975 val = (Object)(str.toUpperCase()); 976 } 977 this.initProps.put(key,val); 978 } 979 replaceKey(MAG_KEY, saveMagStr); 980 magStr = getKey(baseSource, MAG_KEY); 981 vals = StringUtil.split(magStr, " ", 2); 982 iVal = Integer.valueOf(vals[0]); 983 lMag = iVal.intValue(); 984 iVal = Integer.valueOf(vals[1]); 985 eMag = iVal.intValue(); 986 987 this.initProps.put("LRES", String.valueOf((this.lRes))); 988 this.initProps.put("ERES", String.valueOf((this.eRes))); 989 this.initProps.put("PLRES", String.valueOf((this.previewLineRes))); 990 this.initProps.put("PERES", String.valueOf((this.previewEleRes))); 991 this.previewProjection = (MapProjection)acs; 992 993 String coordType = ""; 994 double coords[] = { 0.0, 0.0 }; 995 996 logger.trace("basically={} laLoSel==null?={}", basically, (this.laLoSel==null)); 997 if (!basically) { 998 if (this.laLoSel != null) { 999 coordType = this.laLoSel.getCoordinateType(); 1000 if (coordType.equals(this.laLoSel.getLatLonType())) { 1001 coords[0] = this.laLoSel.getLatitude(); 1002 coords[1] = this.laLoSel.getLongitude(); 1003 } else { 1004 coords[0] = (double)this.laLoSel.getLine(); 1005 coords[1] = (double)this.laLoSel.getElement(); 1006 } 1007 1008 // turns out that laLoSel is reused for datachoices 1009 // from the same source. if you don't update laLoSel's 1010 // dataChoice, it'll apply whatever data selection 1011 // you set up... to the first data choice that you 1012 // loaded! (and causing an NPE when attempting to 1013 // bundle the dataselection for the newly-selected 1014 // datachoice. 1015 this.previewSel.setDataChoice(dataChoice); 1016 this.laLoSel.setDataChoice(dataChoice); 1017 this.laLoSel.setPreviewLineRes(this.previewLineRes); 1018 this.laLoSel.setPreviewEleRes(this.previewEleRes); 1019 this.laLoSel.update(previewDir, this.previewProjection, previewNav, 1020 coordType, coords); 1021 1022 } else { 1023 this.laLoSel = new GeoLatLonSelection(this, 1024 dataChoice, this.initProps, this.previewProjection, 1025 previewDir, previewNav); 1026 this.lineMag = this.laLoSel.getLineMag(); 1027 this.elementMag = this.laLoSel.getElementMag(); 1028 } 1029 } else { 1030 if (this.laLoSel != null) { 1031 this.previewSel.setDataChoice(dataChoice); 1032 this.laLoSel.setDataChoice(dataChoice); 1033 } 1034 } 1035 /* DAVEP: Force preview on. "No preview" means blank image */ 1036// this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 1037// this.laLoSel, this.previewProjection, 1038// this.lineMag, this.elementMag, this.showPreview); 1039 logger.trace("even reaching this point?"); 1040 this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 1041 this.laLoSel, this.previewProjection, 1042 this.lineMag, this.elementMag, showPreview); 1043 logger.trace("how about this one?"); 1044 } catch (Exception e) { 1045 logger.error("problem making selection components", e); 1046 getIdv().showNormalCursor(); 1047 } 1048 this.haveDataSelectionComponents = true; 1049// replaceKey(MAG_KEY, (Object)(this.lineMag + " " + this.elementMag)); 1050 replaceKey(MAG_KEY, (this.lineMag + " " + this.elementMag)); 1051 components.add(this.previewSel); 1052 components.add(this.laLoSel); 1053 } 1054 } 1055 if (this.previewSel != null) { 1056 this.previewSel.initBox(); 1057 } 1058 getIdv().showNormalCursor(); 1059 } 1060 1061 /** 1062 * A hook to allow this data source to add data selection components 1063 * to the IDV field selector 1064 * 1065 * @param dataChoice the data choice 1066 * 1067 * @return list of components 1068 */ 1069// @Override public List<DataSelectionComponent> getDataSelectionComponents(DataChoice dataChoice) { 1070//// List<DataSelectionComponent> dataSelectionComponents = new ArrayList<DataSelectionComponent>(); 1071//// initDataSelectionComponents(dataSelectionComponents, dataChoice); 1072//// return dataSelectionComponents; 1073// return new ArrayList<DataSelectionComponent>(); 1074// } 1075 1076 private boolean makePreviewImage(DataChoice dataChoice) { 1077 logger.trace("Starting with dataChoice={}", dataChoice); 1078 getIdv().showWaitCursor(); 1079 1080 // For dealing with derived fields - will need to know which bands are involved 1081 // They may be a mix of base resolutions 1082 ArrayList<Integer> derivedBands = new ArrayList<Integer>(); 1083 1084 // TJJ Inq #2181 Feb 2020 1085 // If derived, figure out which bands are involved. Open to better ideas here :-) 1086 if (dataChoice instanceof DerivedDataChoice) { 1087 derivedBandLineRes.clear(); 1088 derivedBandElemRes.clear(); 1089 derivedBandMagFactor.clear(); 1090 isDerived = true; 1091 Hashtable ht = ((DerivedDataChoice) dataChoice).getUserSelectedChoices(); 1092 java.util.Set<String> set = ht.keySet(); 1093 for (String s : set) { 1094 DataChoice dc = (DataChoice) ht.get(s); 1095 logger.debug("Data choice String ID " + dc.getStringId()); 1096 logger.debug("Data choice Name " + dc.getName()); 1097 String dcName = dc.getName(); 1098 // Pull out band number, definitely hacky but don't know a better way 1099 int idxLo = dcName.indexOf("Band") + 4; 1100 int idxHi = dcName.indexOf('_', idxLo); 1101 String bandStr = dcName.substring(idxLo, idxHi); 1102 logger.debug("Data choice Band " + bandStr); 1103 derivedBands.add(Integer.parseInt(bandStr)); 1104 Hashtable dcProps = dc.getProperties(); 1105 } 1106 } else { 1107 isDerived = false; 1108 } 1109 1110 boolean msgFlag = false; 1111 showPreview = saveShowPreview; 1112 List<BandInfo> bandInfos = (List<BandInfo>)getProperty(PROP_BANDINFO, (Object) null); 1113 BandInfo bi = null; 1114 1115 String saveBand = getKey(source, BAND_KEY); 1116 1117 int bandIdx = 0; 1118 int sensorID = -1; 1119 1120 logger.trace("band index stuff: saveBand={}, bandIdx={}, source={}", new Object[] { saveBand, bandIdx, source }); 1121 List<TwoFacedObject> calList = null; 1122 try { 1123 Object dcObj = dataChoice.getId(); 1124 if (dcObj instanceof BandInfo) { 1125 bi = (BandInfo) dcObj; 1126 Integer bandInt = Integer.valueOf(bandInfos.indexOf(dcObj)+1); 1127 saveBand = bandInt.toString(); 1128 } else { 1129 msgFlag = true; 1130 bi = bandInfos.get(bandIdx); 1131 this.showPreview = false; 1132 // If derived, use band representing best available res 1133 if (isDerived) { 1134 this.showPreview = true; 1135 double bestRes = Double.MAX_VALUE; 1136 int tmpIdx = 0; 1137 for (BandInfo bandInfo : bandInfos) { 1138 AreaDirectory ad = (AreaDirectory) allBandDirs.get(bandInfo.getBandNumber()); 1139 double lineRes = ad.getCenterLatitudeResolution(); 1140 double elemRes = ad.getCenterLongitudeResolution(); 1141 if (derivedBands.contains(bandInfo.getBandNumber())) { 1142 int tmpBand = bandInfo.getBandNumber(); 1143 derivedBandLineRes.put(tmpBand, lineRes); 1144 derivedBandElemRes.put(tmpBand, elemRes); 1145 } 1146 if (lineRes < bestRes && (derivedBands.contains(bandInfo.getBandNumber()))) { 1147 bestRes = lineRes; 1148 bandIdx = tmpIdx; 1149 logger.debug("Derived field, updated bandIdx to: " + bandIdx); 1150 bi = bandInfo; 1151 saveBand = String.valueOf(bi.getBandNumber()); 1152 logger.debug("Updated bandInfo: " + bi); 1153 } 1154 tmpIdx++; 1155 } 1156 // Now that we've got all the derived bands and resolutions, 1157 // set multipliers for line/elem ranges based on mixtures of resolutions 1158 boolean allThree = false; 1159 boolean twoLower = false; 1160 boolean twoHigher = false; 1161 boolean allSame = true; 1162 Collection<Double> resVals = (Collection<Double>) derivedBandLineRes.values(); 1163 if (resVals.contains(0.5)) { 1164 if (resVals.contains(1.0)) { 1165 if (resVals.contains(2.0)) { 1166 allThree = true; 1167 allSame = false; 1168 } else { 1169 twoLower = true; 1170 allSame = false; 1171 } 1172 } 1173 } else { 1174 if (resVals.contains(1.0)) { 1175 if (resVals.contains(2.0)) { 1176 twoHigher = true; 1177 allSame = false; 1178 } 1179 } 1180 } 1181 1182 for (Integer bandNum : derivedBandLineRes.keySet()) { 1183 1184 Double bandRes = derivedBandLineRes.get(bandNum); 1185 if (allSame) { 1186 derivedBandMagFactor.put(bandNum, 1); 1187 } 1188 if (twoLower) { 1189 if (bandRes < 1) { 1190 derivedBandMagFactor.put(bandNum, 1); 1191 } else { 1192 derivedBandMagFactor.put(bandNum, 2); 1193 } 1194 } 1195 if (twoHigher) { 1196 if (bandRes > 1) { 1197 derivedBandMagFactor.put(bandNum, 2); 1198 } else { 1199 derivedBandMagFactor.put(bandNum, 1); 1200 } 1201 } 1202 if (allThree) { 1203 if (bandRes > 1) { 1204 derivedBandMagFactor.put(bandNum, 4); 1205 } else { 1206 if (bandRes < 1) { 1207 derivedBandMagFactor.put(bandNum, 1); 1208 } else { 1209 derivedBandMagFactor.put(bandNum, 2); 1210 } 1211 } 1212 } 1213 } 1214 1215 // Print all mags for verification 1216 derivedBandMagFactor.entrySet().forEach(entry -> { 1217 logger.debug("Derived Mag Band : " + entry.getKey() + " Mag Value : " + entry.getValue()); 1218 }); 1219 1220 } 1221 } 1222 // pull out the list of cal units, we'll need for type check later... 1223 calList = bi.getCalibrationUnits(); 1224 1225 // TJJ Dec 2017 1226 // Kinda hacky (but then again so is this entire class) :-/ 1227 // Do our GEO speedup code for known GEO sensor IDs 1228 sensorID = bi.getSensor(); 1229 if (sensorIsGEO(sensorID)) { 1230 isGeoSensor = true; 1231 } 1232 if (sensorIsABI(sensorID)) { 1233 isABISensor = true; 1234 } 1235 1236 logger.trace("replacing band: new={} from={}", bi.getBandNumber(), source); 1237 source = replaceKey(source, BAND_KEY, bi.getBandNumber()); 1238 // if we're replacing the band, replace cal type with preferred type for that band 1239 logger.trace("replacing unit: new={} from={}", bi.getPreferredUnit(), source); 1240 source = replaceKey(source, UNIT_KEY, bi.getPreferredUnit()); 1241 } catch (Exception excp) { 1242 handlePreviewImageError(1, excp); 1243 } 1244 String name = dataChoice.getName(); 1245 int idx = name.lastIndexOf('_'); 1246 String unit = name.substring(idx + 1); 1247 1248 // if this is not a valid cal unit (e.g. could be set to a plugin formula name) 1249 // set it to something valid 1250 boolean validCal = false; 1251 for (TwoFacedObject tfo : calList) { 1252 if (unit.equals((String) tfo.getId())) { 1253 validCal = true; 1254 break; 1255 } 1256 } 1257 if (!validCal) { 1258 unit = bi.getPreferredUnit(); 1259 } 1260 1261 if (getKey(source, UNIT_KEY).length() == 0) { 1262 logger.trace("non-empty unit, replacing: new={} from={}", unit, source); 1263// source = replaceKey(source, UNIT_KEY, (Object)(unit)); 1264 source = replaceKey(source, UNIT_KEY, unit); 1265 } 1266 1267 AddeImageDescriptor aid = null; 1268 while (aid == null) { 1269 try { 1270 logger.trace("creating new AddeImageDescriptor from {}", this.source); 1271 aid = new AddeImageDescriptor(this.source); 1272 } catch (Exception excp) { 1273 msgFlag = true; 1274 if (bandIdx > (bandInfos.size() - 1)) { 1275 getIdv().showNormalCursor(); 1276 return false; 1277 } 1278 1279 bi = bandInfos.get(bandIdx); 1280 logger.trace("replacing band: new={} from={}", bi.getBandNumber(), source); 1281// source = replaceKey(source, BAND_KEY, (Object)(bi.getBandNumber())); 1282 source = replaceKey(source, BAND_KEY, bi.getBandNumber()); 1283 ++bandIdx; 1284 } 1285 } 1286// previewDir = getPreviewDirectory(aid); 1287 AddeImageDescriptor previewDescriptor = getPreviewDirectory(aid, dataChoice); 1288 previewDir = previewDescriptor.getDirectory(); 1289 1290 // On the off chance user is working with ABI MESO or AHI TARGET sectors, 1291 // *and* they have polling on, we need to turn auto-set projection off 1292 // since the domain can shift around 1293 1294 if (isABISensor) { 1295 String memo = previewDir.getMemoField().toLowerCase(); 1296 boolean isMesoOrTarget = false; 1297 boolean offScreen = getIdv().getArgsManager().getIsOffScreen(); 1298 if ((memo.contains("meso")) || (memo.contains("targ"))) isMesoOrTarget = true; 1299 1300 // alert user that bundle data may have geographically relocated, if they used relative times 1301 if (fromBundle && isMesoOrTarget) { 1302 boolean bundleDialog = getIdv().getStore().get(Constants.PREF_RELATIVE_TIME_BUNDLE, false); 1303 // don't create a dialog though if we are running in background/offscreen mode 1304 if (! offScreen) { 1305 if (! bundleDialog) { 1306 String msg = "Your bundle contains a targeted sector (e.g. ABI MESO).\n" + 1307 "These domains can shift geographically, to focus on regional events. \n" + 1308 "If you do not see your satellite image, zoom your display out, it may have moved.\n"; 1309 JCheckBox jcbPlugin = new JCheckBox("Do not show this message again"); 1310 Object[] params = { msg, jcbPlugin }; 1311 JOptionPane.showMessageDialog( 1312 null, params, "Bundle with Relative Time ADDE Request(s)", JOptionPane.OK_OPTION 1313 ); 1314 boolean dontShow = jcbPlugin.isSelected(); 1315 getIdv().getStore().put(Constants.PREF_RELATIVE_TIME_BUNDLE, dontShow); 1316 } 1317 } else { 1318 logger.warn("Note: Bundle with MESO or TARGET sector, data may have geographically relocated!"); 1319 } 1320 } 1321 1322 logger.info("Preview Directory memo field: " + memo); 1323 if (isPolling() && isMesoOrTarget) { 1324 MapViewManager mvm = (MapViewManager) getIdv().getViewManager(); 1325 mvm.setUseProjectionFromData(false); 1326 if (! domainShiftNoticeTargetShown) { 1327 if (! offScreen) { 1328 String msg = "You currently have polling active, and are working with\n" + 1329 "a targeted sector (e.g. ABI MESO). Since these domains can\n" + 1330 "shift geographically, auto-set projection has been turned off.\n"; 1331 Object[] params = { msg }; 1332 JOptionPane.showMessageDialog(null, params, "Notice", JOptionPane.OK_OPTION); 1333 domainShiftNoticeTargetShown = true; 1334 } else { 1335 logger.warn("Note: Polling with shifting sector - auto-set projection turned off"); 1336 } 1337 } 1338 } 1339 } 1340 1341 logger.trace("using previewDir={}", previewDir); 1342// try { 1343// logger.trace("preview areadir: stlines={} stelements={} lines={} elements={}", new Object[] { previewDir.getValue(AreaFile.AD_STLINE), previewDir.getValue(AreaFile.AD_STELEM), previewDir.getLines(), previewDir.getElements() }); 1344// } catch (Exception e) { 1345// logger.error("error logging areadir preview", e); 1346// } 1347 int eMag = 1; 1348 int lMag = 1; 1349 int eSize = 1; 1350 int lSize = 1; 1351 try { 1352 int plMag = 1; 1353 int peMag = 1; 1354 Object magKey = (Object) "mag"; 1355 if (sourceProps.containsKey(magKey)) { 1356 String magVal = (String)(sourceProps.get(magKey)); 1357 String[] magVals = magVal.split(" "); 1358 peMag = Integer.parseInt(magVals[0]); 1359 plMag = Integer.parseInt(magVals[1]); 1360 } 1361 double feSize = (double) previewDir.getElements(); 1362 double flSize = (double) previewDir.getLines(); 1363 double feMag = (double) peMag; 1364 double flMag = (double) plMag; 1365 if (feSize > flSize) { 1366 feMag = feSize / 525.0; 1367 flMag = feMag * (double) plMag / (double) peMag; 1368 } else { 1369 flMag = flSize/500.0; 1370 feMag = flMag * (double) peMag / (double) plMag; 1371 } 1372 eMag = (int) Math.ceil(feMag); 1373 lMag = (int) Math.ceil(flMag); 1374 } catch(Exception excp) { 1375 handlePreviewImageError(3, excp); 1376 } 1377 if (eMag < 1) eMag = 1; 1378 if (lMag < 1) lMag = 1; 1379 1380 eSize = 525; 1381 lSize = 500; 1382 if ((baseSource == null) || msgFlag) { 1383 logger.trace("replacing\nbaseSource={}\nsource={}", baseSource, source); 1384 baseSource = source; 1385 } 1386 this.previewLineRes = lMag; 1387 this.previewEleRes = eMag; 1388 String uLStr = "0 0 F"; 1389 // MJH getting uLStr from previewDir here breaks Himawari-8, 1390 // and is apparently unnecessary in general, so just use "0 0 F" always. 1391 // try { 1392 // int startLine = previewDir.getValue(AreaFile.AD_STLINE); 1393 // int startEle = previewDir.getValue(AreaFile.AD_STELEM); 1394 // uLStr = startLine + " " + startEle + " I"; 1395 // } catch (Exception e) { 1396 // } 1397// String src = aid.getSource(); 1398 String src = previewDescriptor.getSource(); 1399 logger.trace("building preview request from src={}", src); 1400 1401 src = removeKey(src, LATLON_KEY); 1402 src = replaceKey(src, LINELE_KEY, uLStr); 1403 src = replaceKey(src, PLACE_KEY, "ULEFT"); 1404 src = replaceKey(src, SIZE_KEY,(lSize + " " + eSize)); 1405 src = replaceKey(src, MAG_KEY, (lMag + " " + eMag)); 1406 src = replaceKey(src, BAND_KEY, bi.getBandNumber()); 1407 src = replaceKey(src, UNIT_KEY, unit); 1408 1409// if (aid.getIsRelative()) { 1410// logger.trace("injecting POS={}", aid.getRelativeIndex()); 1411// src = replaceKey(src, "POS", (Object)aid.getRelativeIndex()); 1412// } 1413// if (previewDescriptor.getIsRelative()) { 1414// logger.trace("inject POS={} into src={}", previewDescriptor.getRelativeIndex(), src); 1415// src = replaceKey(src, "POS", (Object)previewDescriptor.getRelativeIndex()); 1416// src = replaceKey(src, "POS", previewDescriptor.getRelativeIndex()); 1417// } 1418 1419 logger.trace("creating AddeImageDescriptor from src={}", src); 1420 try { 1421 aid = new AddeImageDescriptor(src); 1422 } catch (Exception excp) { 1423 handlePreviewImageError(4, excp); 1424 src = replaceKey(src, BAND_KEY, saveBand); 1425 aid = new AddeImageDescriptor(src); 1426 src = replaceKey(src, BAND_KEY, bi.getBandNumber()); 1427 } 1428 if (msgFlag && (!"ALL".equals(saveBand))) { 1429 src = replaceKey(src, BAND_KEY, saveBand); 1430 } 1431 logger.trace("overwriting\nbaseSource={}\nsrc={}", baseSource, src); 1432 baseSource = src; 1433 getIdv().showNormalCursor(); 1434 return true; 1435 } 1436 1437 /** 1438 * Return true if the Sensor is ABI variant (ABI, AHI, AMI) 1439 * These sensors have MESO sectors which move around geospatially 1440 * 1441 * @param sensorID McIDAS Sensor Source number. 1442 * See https://www.ssec.wisc.edu/mcidas/doc/users_guide/2017.2/app_c-1.html 1443 * @return true if ID matches a defined ABI sensor 1444 */ 1445 1446 private boolean sensorIsABI(int sensorID) { 1447 1448 boolean isABI = false; 1449 1450 // GOES 16 - 19 1451 if (sensorID == 186) isABI = true; 1452 if (sensorID == 188) isABI = true; 1453 if (sensorID == 190) isABI = true; 1454 if (sensorID == 192) isABI = true; 1455 1456 // Himawari-8 and Himawari-9 1457 if (sensorID == 86) isABI = true; 1458 if (sensorID == 286) isABI = true; 1459 if (sensorID == 287) isABI = true; 1460 if (sensorID == 288) isABI = true; 1461 if (sensorID == 289) isABI = true; 1462 1463 return isABI; 1464 } 1465 1466 /** 1467 * Return true if the Sensor is Geostationary 1468 * 1469 * @param sensorID McIDAS Sensor Source number. 1470 * See https://www.ssec.wisc.edu/mcidas/doc/users_guide/2017.2/app_c-1.html 1471 * @return true if ID matches a defined GEO sensor 1472 */ 1473 1474 private boolean sensorIsGEO(int sensorID) { 1475 boolean isGEO = false; 1476 1477 // early GEO through FY 1478 if ((sensorID >= 12) && (sensorID <= 40)) isGEO = true; 1479 1480 // Meteosat 1481 if ((sensorID >= 51) && (sensorID <= 58)) isGEO = true; 1482 if (sensorID == 354) isGEO = true; 1483 1484 // GOES 8 - 12 1485 if ((sensorID >= 70) && (sensorID <= 79)) isGEO = true; 1486 1487 // GMS, MTSAT (which is actually pre-8 Himawari), H-8/9 1488 if ((sensorID >= 82) && (sensorID <= 86)) isGEO = true; 1489 if ((sensorID >= 286) && (sensorID <= 288)) isGEO = true; 1490 1491 // Feng Yun 1492 if ((sensorID >= 95) && (sensorID <= 97)) isGEO = true; 1493 if ((sensorID >= 275) && (sensorID <= 277)) isGEO = true; 1494 1495 // GOES 13 - 19 1496 // NOTE: through all four GOES-R series satellites 1497 if ((sensorID >= 180) && (sensorID <= 193)) isGEO = true; 1498 1499 // Kalpana and INSAT 1500 if ((sensorID >= 230) && (sensorID <= 232)) isGEO = true; 1501 1502 // COMS 1503 if (sensorID == 250) isGEO = true; 1504 1505 return isGEO; 1506 } 1507 1508 /** 1509 * Show the given error to the user. 1510 * 1511 * @param excp The exception 1512 */ 1513 protected void handlePreviewImageError(int flag, Exception excp) { 1514 getIdv().showNormalCursor(); 1515 LogUtil.userErrorMessage("Error in makePreviewImage e=" + flag + " " + excp); 1516 } 1517 1518 public static String removeKey(String src, String key) { 1519 String returnString = src; 1520 key = key.toUpperCase() + '='; 1521 if (returnString.contains(key)) { 1522 String[] segs = returnString.split(key); 1523 String seg0 = segs[0]; 1524 String seg1 = segs[1]; 1525 int indx = seg1.indexOf('&'); 1526 if (indx >= 0) { 1527 seg1 = seg1.substring(indx + 1); 1528 } 1529 returnString = seg0 + seg1; 1530 } 1531 return returnString; 1532 } 1533 1534 public static String replaceKey(String sourceUrl, String key, Object value) { 1535 String returnString = sourceUrl; 1536 1537 // make sure we got valid key/value pair 1538 if ((key == null) || (value == null)) { 1539 return returnString; 1540 } 1541 1542 key = key.toUpperCase() + '='; 1543 String strValue = value.toString(); 1544 if (returnString.contains(key)) { 1545 String[] segs = returnString.split(key); 1546 String seg0 = segs[0]; 1547 String seg1 = segs[1]; 1548 int indx = seg1.indexOf('&'); 1549 if (indx < 0) { 1550 seg1 = ""; 1551 } else if (indx > 0) { 1552 seg1 = seg1.substring(indx); 1553 } 1554 returnString = seg0 + key + strValue + seg1; 1555 } else { 1556 returnString = returnString + '&' + key + strValue; 1557 } 1558 1559 // if key is for cal units, and it was changed to BRIT, 1560 // must change the spacing key too 1561 if ((key.equals(UNIT_KEY + '=')) && ("BRIT".equals(strValue))) { 1562 returnString = replaceKey(returnString, SPAC_KEY, SPAC_KEY, SPACING_BRIT); 1563 } else { 1564 returnString = replaceKey(returnString, SPAC_KEY, SPAC_KEY, SPACING_NON_BRIT); 1565 } 1566 return returnString; 1567 } 1568 1569 public static String replaceKey(String src, String oldKey, String newKey, Object value) { 1570 String returnString = src; 1571 oldKey = oldKey.toUpperCase() + '='; 1572 newKey = newKey.toUpperCase() + '='; 1573 if (returnString.contains(oldKey)) { 1574 String[] segs = returnString.split(oldKey); 1575 String seg0 = segs[0]; 1576 String seg1 = segs[1]; 1577 int indx = seg1.indexOf('&'); 1578 if (indx < 0) { 1579 seg1 = ""; 1580 } else if (indx > 0) { 1581 seg1 = seg1.substring(indx); 1582 } 1583 returnString = seg0 + newKey + value.toString() + seg1; 1584 } 1585 else { 1586 returnString = returnString + '&' + newKey + value.toString(); 1587 } 1588 return returnString; 1589 } 1590 1591 private <T> void replaceKey(String key, T value) { 1592 baseSource = replaceKey(baseSource, key, value); 1593 } 1594 1595 public static String getKey(String src, String key) { 1596 String returnString = ""; 1597 key = key.toUpperCase() + '='; 1598 if (src.contains(key)) { 1599 String[] segs = src.split(key); 1600 segs = segs[1].split("&"); 1601 returnString = segs[0]; 1602 } 1603 return returnString; 1604 } 1605 1606 1607 /** 1608 * Create the set of {@link ucar.unidata.data.DataChoice} that represent 1609 * the data held by this data source. We create one top-level 1610 * {@link ucar.unidata.data.CompositeDataChoice} that represents 1611 * all of the image time steps. We create a set of children 1612 * {@link ucar.unidata.data.DirectDataChoice}, one for each time step. 1613 */ 1614 1615 public void doMakeDataChoices() { 1616 super.doMakeDataChoices(); 1617 List<BandInfo> bandInfos = (List<BandInfo>) getProperty(PROP_BANDINFO, (Object) null); 1618 String name = ""; 1619 if (this.choiceName != null) { 1620 name = this.choiceName; 1621 } 1622 if (name.length() != 0) { 1623 logger.trace("already have a name={}", name); 1624 return; 1625 } 1626 if (!sourceProps.containsKey(UNIT_KEY)) { 1627 logger.trace("sourceProps has no unit key={}", sourceProps); 1628 return; 1629 } 1630 BandInfo bi = null; 1631 if (sourceProps.containsKey(BAND_KEY)) { 1632 int bandProp = Integer.parseInt((String)(sourceProps.get(BAND_KEY))); 1633 int bandIndex = BandInfo.findIndexByNumber(bandProp, bandInfos); 1634 bi = (BandInfo)bandInfos.get(bandIndex); 1635 if (sourceProps.containsKey(UNIT_KEY)) { 1636 bi.setPreferredUnit((String)(sourceProps.get(UNIT_KEY))); 1637 } else { 1638 bi.setPreferredUnit(""); 1639 } 1640 name = makeBandParam(bi); 1641 } 1642 else if (sourceProps.containsKey(BANDINFO_KEY)) { 1643 ArrayList al = (ArrayList) sourceProps.get(BANDINFO_KEY); 1644 bi = (BandInfo) al.get(0); 1645 name = makeBandParam(bi); 1646 } 1647 if (stashedChoices != null) { 1648 int numChoices = stashedChoices.size(); 1649 for (int i = 0; i < numChoices; i++) { 1650 DataChoice choice = (DataChoice) stashedChoices.get(i); 1651 if (name.equals(choice.getName())) { 1652 setProperty(PROP_DATACHOICENAME, choice.getName()); 1653 } 1654 } 1655 } 1656 } 1657 1658 /** 1659 * Overridden so that McIDAS-V can <i>attempt</i> to return the correct 1660 * {@code DataSelection} for the current {@code DataChoice}. 1661 */ 1662 1663 @Override public DataSelection getDataSelection() { 1664 DataSelection tmp; 1665 1666 if (this.laLoSel != null) { 1667 logger.trace("* mcv getSelForChoice: choice='{}'", this.laLoSel.getDataChoice()); 1668 tmp = this.getSelForChoice(this.laLoSel.getDataChoice()); 1669 } else { 1670 logger.trace("* idvland getDataSelection laLoSel=null: {}; choiceToSel=null: {}", (this.laLoSel==null), (this.choiceToSel==null)); 1671 tmp = super.getDataSelection(); 1672 } 1673// if (this.laLoSel == null || this.choiceToSel == null || !this.choiceToSel.containsKey(this.laLoSel.getDataChoice())) { 1674// logger.trace("* idvland getDataSelection laLoSel=null: {}; choiceToSel=null: {}", (this.laLoSel==null), (this.choiceToSel==null)); 1675// tmp = super.getDataSelection(); 1676// } else if (this.laLoSel != null) { 1677// logger.trace("* mcv getSelForChoice"); 1678// tmp = this.getSelForChoice(this.laLoSel.getDataChoice()); 1679// } 1680 if (tmp != null) { 1681 logger.trace("return selection props={} geo={}", tmp.getProperties(), tmp.getGeoSelection()); 1682 } else { 1683 logger.trace("return selection props=null geo=null choiceToSel={} :(", this.choiceToSel); 1684 } 1685 return tmp; 1686 } 1687 1688 /** 1689 * Overridden so that McIDAS-V can associate this data source's current 1690 * {@code DataChoice} with the given {@code DataSelection}. 1691 */ 1692 1693 @Override public void setDataSelection(DataSelection s) { 1694 1695 GeoSelection tmp = null; 1696 if (s != null) { 1697 tmp = s.getGeoSelection(); 1698 } 1699 if (tmp != null && this.laLoSel != null) { 1700 GeoLocationInfo bbox = tmp.getBoundingBox(); 1701 GeoLocationInfo laloBbox = this.laLoSel.getGeoLocationInfo(); 1702 tmp.setBoundingBox(laloBbox); 1703 logger.trace("incoming bbox={} laLo bbox={}", bbox, laloBbox); 1704 } 1705 1706 super.setDataSelection(s); 1707 1708 if (this.laLoSel != null) { 1709 this.putSelForChoice(this.laLoSel.getDataChoice(), s); 1710 } else { 1711 logger.trace("laLoSel is null; s={}", s); 1712 } 1713 1714 } 1715 1716 /** 1717 * Insert the new DataChoice into the dataChoice list. 1718 * 1719 * @param choice new choice to add 1720 */ 1721 1722 protected void addDataChoice(DataChoice choice) { 1723 logger.trace("choice={}", choice); 1724 super.addDataChoice(choice); 1725 if (stashedChoices == null) { 1726 stashedChoices = new ArrayList(); 1727 } 1728 stashedChoices.add(choice); 1729 } 1730 1731 /** 1732 * Checks to see if a given {@code AddeImageDescriptor} is based upon a 1733 * local (or remote) file. 1734 * 1735 * <p>The check is pretty simple: is {@code descriptor.getSource()} a valid 1736 * path? 1737 * 1738 * @param descriptor {@code AddeImageDescriptor} of questionable origins. Shouldn't be {@code null}. 1739 * 1740 * @return {@code true} if {@code descriptor}'s source is a valid path. 1741 */ 1742 1743 public static boolean isFromFile(final AddeImageDescriptor descriptor) { 1744 return new File(descriptor.getSource()).exists(); 1745 } 1746 1747 /** 1748 * Create the actual data represented by the given 1749 * {@link ucar.unidata.data.DataChoice}. 1750 * 1751 * @param dataChoice Either the 1752 * {@link ucar.unidata.data.CompositeDataChoice} 1753 * representing all time steps or a 1754 * {@link ucar.unidata.data.DirectDataChoice} 1755 * representing a single time step. 1756 * @param category Not really used. 1757 * @param dataSelection Defines any time subsets. 1758 * @param requestProperties extra request properties 1759 * 1760 * @return The image or image sequence data. 1761 * 1762 * @throws RemoteException Java RMI problem 1763 * @throws VisADException VisAD problem 1764 */ 1765 1766 protected Data getDataInner(DataChoice dataChoice, DataCategory category, 1767 DataSelection dataSelection, 1768 Hashtable requestProperties) 1769 throws VisADException, RemoteException { 1770 Data img = null; 1771 iml = new ArrayList(); 1772 1773 if (dataSelection == null) { 1774 return null; 1775 } 1776 setDataSelection(dataSelection); 1777 1778 // assuming the Double.NaN bbox is easy to replace with 1779 // an actual bbox, the getGeoSelection(createIfNeeded=true) should 1780 // probably populate the geoselection with the Double.NaN bbox. 1781 GeoSelection geoSelection = dataSelection.getGeoSelection(true); 1782 if (geoSelection == null) { 1783 return null; 1784 } 1785 1786 GeoLocationInfo selectionBox = geoSelection.getBoundingBox(); 1787 if (selectionBox == null) { 1788 logger.info("MCV3088: incoming dataselection has null bounding box, replacing with default! dataChoice: '{}', dataSelection: {}", dataChoice.getName(), dataSelection); 1789 selectionBox = new GeoLocationInfo(Double.NaN, Double.NaN, Double.NaN, Double.NaN); 1790 geoSelection.setBoundingBox(selectionBox); 1791 } 1792 1793 boolean validState = geoSelection.getHasValidState(); 1794 if (!validState) { 1795 return null; 1796 } 1797 1798 if (this.lastGeoSelection == null) { 1799 this.lastGeoSelection = geoSelection; 1800 } 1801 1802 this.selectionProps = dataSelection.getProperties(); 1803 Enumeration propEnum = this.selectionProps.keys(); 1804 while (propEnum.hasMoreElements()) { 1805 String key = propEnum.nextElement().toString(); 1806 if (key.compareToIgnoreCase(LATLON_KEY) == 0) { 1807 String val = (String)this.selectionProps.get(key); 1808 if (val.contains("NaN")) { 1809 return img; 1810 } 1811 } 1812 if (key.compareToIgnoreCase(LINELE_KEY) == 0) { 1813 String val = (String)this.selectionProps.get(key); 1814 if (val.contains("NaN")) { 1815 return img; 1816 } 1817 } 1818 } 1819 1820 if (this.selectionProps.containsKey("MAG")) { 1821 String str = (String)this.selectionProps.get("MAG"); 1822 String[] strs = StringUtil.split(str, " ", 2); 1823 this.lineMag = Integer.parseInt(strs[0]); 1824 this.elementMag = Integer.parseInt(strs[1]); 1825 } 1826 this.choiceName = dataChoice.getName(); 1827 if (this.choiceName != null) { 1828 setProperty(PROP_DATACHOICENAME, this.choiceName); 1829 } 1830 try { 1831 img = super.getDataInner(dataChoice, category, dataSelection, requestProperties); 1832 } catch (Exception e) { 1833 String displaySrc = getDisplaySource(); 1834 if (displaySrc != null) { 1835 AddeImageDescriptor aid = new AddeImageDescriptor(displaySrc); 1836 dataChoice.setId((Object)aid); 1837 img = super.getDataInner(dataChoice, category, dataSelection, requestProperties); 1838 } 1839 } 1840 return img; 1841 } 1842 1843 /** 1844 * Check if the DataChoice has a BandInfo for its ID 1845 * 1846 * @param dataChoice choice to check 1847 * 1848 * @return true if the choice ID is a BandInfo 1849 */ 1850 1851 private boolean hasBandInfo(DataChoice dataChoice) { 1852 Object id = dataChoice.getId(); 1853 return id instanceof BandInfo; 1854 } 1855 1856 /** _more_ */ 1857 AreaDirectory[][] currentDirs; 1858 1859 /** 1860 * Create the image sequence defined by the given dataChoice. 1861 * 1862 * @param dataChoice The choice. 1863 * @param subset any time subsets. 1864 * @return The image sequence. 1865 * 1866 * @throws RemoteException Java RMI problem 1867 * @throws VisADException VisAD problem 1868 */ 1869 1870 protected ImageSequence makeImageSequence(DataChoice dataChoice, DataSelection subset) 1871 throws VisADException, RemoteException { 1872 1873// if (dataChoice.getDataSelection() == null) { 1874// dataChoice.setDataSelection(subset); 1875// } 1876 Hashtable subsetProperties = subset.getProperties(); 1877 Enumeration propEnum = subsetProperties.keys(); 1878 int numLines = 0; 1879 int numEles = 0; 1880 while (propEnum.hasMoreElements()) { 1881 String key = propEnum.nextElement().toString(); 1882 if (key.compareToIgnoreCase(SIZE_KEY) == 0) { 1883 String sizeStr = (String)(subsetProperties.get(key)); 1884 String[] vals = StringUtil.split(sizeStr, " ", 2); 1885 Integer iVal = Integer.valueOf(vals[0]); 1886 numLines = iVal.intValue(); 1887 iVal = Integer.valueOf(vals[1]); 1888 numEles = iVal.intValue(); 1889 break; 1890 } 1891 } 1892 1893 if (sampleMapProjection == null) { 1894 String addeCmdBuff = baseSource; 1895 AreaFile af = null; 1896 try { 1897 af = new AreaFile(addeCmdBuff); 1898 } catch (Exception eOpen) { 1899 logger.error("could not open area file: {}", eOpen); 1900 setInError(true); 1901 throw new BadDataException("Opening area file: " + eOpen.getMessage(), eOpen); 1902 } 1903 try { 1904// McIDASAreaProjection map = new McIDASAreaProjection(af); 1905 AREACoordinateSystem acs = new AREACoordinateSystem(af); 1906 sampleMapProjection = (MapProjection)acs; 1907// sampleProjection = map; 1908 } catch (Exception e) { 1909 logger.error("making area projection: {}", e); 1910 setInError(true); 1911 throw new BadDataException("Making area projection: " + e.getMessage(), e); 1912 } 1913 } 1914 AREACoordinateSystem macs = (AREACoordinateSystem) sampleMapProjection; 1915 int[] dirBlk = macs.getDirBlock(); 1916 if (numLines == 0) { 1917 double elelin[][] = new double[2][2]; 1918 double latlon[][] = new double[2][2]; 1919 GeoSelection gs = subset.getGeoSelection(); 1920 GeoLocationInfo gli = gs.getBoundingBox(); 1921 if ((gli == null) && (lastGeoSelection != null)) { 1922 subset.setGeoSelection(lastGeoSelection); 1923 gs = lastGeoSelection; 1924 gli = gs.getBoundingBox(); 1925 } 1926 LatLonPoint llp = gli.getUpperLeft(); 1927 latlon[0][0] = llp.getLatitude(); 1928 latlon[1][0] = llp.getLongitude(); 1929 llp = gli.getLowerRight(); 1930 latlon[0][1] = llp.getLatitude(); 1931 latlon[1][1] = llp.getLongitude(); 1932 elelin = macs.fromReference(latlon); 1933 numLines = (int)(Math.abs(elelin[1][0] - elelin[1][1]))*dirBlk[11]; 1934 numEles = (int)(Math.abs(elelin[0][1] - elelin[0][0]))*dirBlk[12]; 1935 } 1936 1937 try { 1938 descriptorsToUse = new ArrayList(); 1939 if (hasBandInfo(dataChoice)) { 1940 descriptorsToUse = getDescriptors(dataChoice, subset); 1941 } else { 1942 List choices = (dataChoice instanceof CompositeDataChoice) 1943 ? getChoicesFromSubset( 1944 (CompositeDataChoice) dataChoice, subset) 1945 : Arrays.asList(new DataChoice[] { 1946 dataChoice }); 1947 for (Iterator iter = choices.iterator(); iter.hasNext(); ) { 1948 DataChoice subChoice = (DataChoice) iter.next(); 1949 AddeImageDescriptor aid = 1950 getDescriptor(subChoice.getId()); 1951 if (aid == null) { 1952 continue; 1953 } 1954 DateTime dttm = aid.getImageTime(); 1955 if ((subset != null) && (dttm != null)) { 1956 List times = getTimesFromDataSelection(subset, 1957 dataChoice); 1958 if ((times != null) && (times.indexOf(dttm) == -1)) { 1959 continue; 1960 } 1961 } 1962 descriptorsToUse.add(aid); 1963 } 1964 } 1965 1966 if (descriptorsToUse == null || descriptorsToUse.size() == 0) { 1967 return null; 1968 } 1969 AddeImageInfo biggestPosition = null; 1970 int pos = 0; 1971 boolean anyRelative = false; 1972 // Find the descriptor with the largest position 1973 for (Iterator iter = descriptorsToUse.iterator(); iter.hasNext(); ) { 1974 AddeImageDescriptor aid = (AddeImageDescriptor) iter.next(); 1975 if (aid.getIsRelative()) { 1976 anyRelative = true; 1977 } 1978 AddeImageInfo aii = aid.getImageInfo(); 1979 1980 // Are we dealing with area files here? 1981 if (aii == null) { 1982 break; 1983 } 1984 1985 // Check if this is absolute time 1986 if ((aii.getStartDate() != null) || (aii.getEndDate() != null)) { 1987 biggestPosition = null; 1988 break; 1989 } 1990 if ((biggestPosition == null) || (Math.abs(aii.getDatasetPosition()) > pos)) { 1991 pos = Math.abs(aii.getDatasetPosition()); 1992 biggestPosition = aii; 1993 } 1994 } 1995 1996 if (getCacheDataToDisk() && anyRelative && (biggestPosition != null)) { 1997 biggestPosition.setRequestType(AddeImageInfo.REQ_IMAGEDIR); 1998 AreaDirectoryList adl = new AreaDirectoryList(biggestPosition.getURLString()); 1999 biggestPosition.setRequestType(AddeImageInfo.REQ_IMAGEDATA); 2000 currentDirs = adl.getSortedDirs(); 2001 } else { 2002 currentDirs = null; 2003 } 2004 2005 int cnt = 1; 2006 DataChoice parent = dataChoice.getParent(); 2007 final List<SingleBandedImage> images = new ArrayList<SingleBandedImage>(); 2008 MathType rangeType = null; 2009 for (Iterator iter = descriptorsToUse.iterator(); iter.hasNext(); ) { 2010 final AddeImageDescriptor aid = (AddeImageDescriptor) iter.next(); 2011 if (currentDirs != null) { 2012 int idx = Math.abs(aid.getImageInfo().getDatasetPosition()); 2013 if (idx >= currentDirs.length) { 2014 continue; 2015 } 2016 } 2017 2018 String label = ""; 2019 if (parent != null) { 2020 label = label + parent.toString() + ' '; 2021 } else { 2022 DataCategory displayCategory = dataChoice.getDisplayCategory(); 2023 if (displayCategory != null) { 2024 label = label + displayCategory + ' '; 2025 } 2026 } 2027 label = label + dataChoice.toString(); 2028 final String readLabel = "Time: " + (cnt++) + '/' 2029 + descriptorsToUse.size() + ' ' 2030 + label; 2031 2032 String src = aid.getSource(); 2033 if (!isFromFile(aid)) { 2034 try { 2035 src = replaceKey(src, LINELE_KEY, (Object)("1 1")); 2036 String sizeString = "10 10"; 2037 src = replaceKey(src, SIZE_KEY, (Object)(sizeString)); 2038 String name = dataChoice.getName(); 2039 int idx = name.lastIndexOf('_'); 2040 String unit = name.substring(idx+1); 2041 if (getKey(src, UNIT_KEY).length() == 0) { 2042 src = replaceKey(src, UNIT_KEY, (Object)(unit)); 2043 } 2044 int lSize = numLines; 2045 int eSize = numEles; 2046 2047 int magFactor = 1; 2048 2049 // TJJ Mar 2020 - For derived fields, see if product bands are mixed-resolution bands 2050 if (isDerived) { 2051 int derivedBandNum = Integer.parseInt(getKey(src, BAND_KEY)); 2052 magFactor = derivedBandMagFactor.get(derivedBandNum); 2053 } 2054 2055 sizeString = lSize / magFactor + " " + eSize / magFactor; 2056 src = replaceKey(src, SIZE_KEY, (Object) (sizeString)); 2057 src = replaceKey(src, MAG_KEY, (Object) (this.lineMag + " " + this.elementMag)); 2058 aid.setSource(src); 2059 logger.debug("makeImageSequence src: " + src); 2060 } catch (Exception exc) { 2061 logger.error("error trying to adjust AddeImageDescriptor: {}", exc); 2062 super.makeImageSequence(dataChoice, subset); 2063 } 2064 } 2065 2066 try { 2067 SingleBandedImage image = makeImage(aid, rangeType, true, readLabel, subset); 2068 if (image != null) { 2069 if(rangeType==null) { 2070 rangeType = ((FunctionType) image.getType()).getRange(); 2071 } 2072 synchronized (images) { 2073 images.add(image); 2074 } 2075 } 2076 } catch (VisADException e) { 2077 logger.error("avoiding visad exception: ",e); 2078 } catch (RemoteException e) { 2079 logger.error("avoiding remote exception: ", e); 2080 } 2081 } 2082 2083 TreeMap imageMap = new TreeMap(); 2084 for (SingleBandedImage image : images) { 2085 imageMap.put(image.getStartTime(), image); 2086 } 2087 List<SingleBandedImage> sortedImages = (List<SingleBandedImage>) new ArrayList(imageMap.values()); 2088 if ((sortedImages.size() > 0) && (sortedImages.get(0) instanceof AreaImageFlatField)) { 2089 DataRange[] sampleRanges = null; 2090 Set domainSet = null; 2091 for (SingleBandedImage sbi : sortedImages) { 2092 AreaImageFlatField aiff = (AreaImageFlatField) sbi; 2093 sampleRanges = aiff.getRanges(true); 2094 if (domainSet == null) { 2095 domainSet = aiff.getDomainSet(); 2096 } 2097 if ((sampleRanges != null) && (sampleRanges.length > 0)) { 2098 for (int rangeIdx = 0; rangeIdx < sampleRanges.length; rangeIdx++) { 2099 DataRange r = sampleRanges[rangeIdx]; 2100 if (Double.isInfinite(r.getMin()) || Double.isInfinite(r.getMax())) { 2101 sampleRanges = null; 2102 break; 2103 } 2104 } 2105 } 2106 if (sampleRanges != null) { 2107 break; 2108 } 2109 } 2110 2111 if (sampleRanges != null) { 2112 for (SingleBandedImage sbi : sortedImages) { 2113 AreaImageFlatField aiff = (AreaImageFlatField) sbi; 2114 aiff.setSampleRanges(sampleRanges); 2115 aiff.setDomainIfNeeded(domainSet); 2116 } 2117 } 2118 } 2119 2120 SingleBandedImage[] imageArray = 2121 (SingleBandedImage[]) sortedImages.toArray( 2122 new SingleBandedImage[sortedImages.size()]); 2123 FunctionType imageFunction = 2124 (FunctionType) imageArray[0].getType(); 2125 FunctionType ftype = new FunctionType(RealType.Time, 2126 imageFunction); 2127 2128 return new ImageSequenceImpl(ftype, imageArray); 2129 } catch (Exception exc) { 2130 throw new ucar.unidata.util.WrapperException(exc); 2131 } 2132 2133 } 2134 2135 /** 2136 * Create the single image defined by the given 2137 * {@link ucar.unidata.data.imagery.AddeImageDescriptor AddeImageDescriptor}. 2138 * 2139 * @param aid Holds image directory and location of the desired image. 2140 * @param rangeType {@literal "rangeType"} to use (if non-{@code null}). 2141 * @param fromSequence _more_ 2142 * @param readLabel 2143 * @param subset geographical subsetting info 2144 * 2145 * @return The data. 2146 * 2147 * @throws RemoteException Java RMI problem 2148 * @throws VisADException VisAD problem 2149 */ 2150 2151 private SingleBandedImage makeImage(AddeImageDescriptor aid, 2152 MathType rangeType, 2153 boolean fromSequence, 2154 String readLabel, DataSelection subset) 2155 throws VisADException, RemoteException { 2156 2157 if (aid == null) { 2158 return null; 2159 } 2160 2161 logger.trace("incoming src={} DateTime={} readLabel={}", new Object[] { aid.getSource(), aid.getImageTime(), readLabel }); 2162 String src = aid.getSource(); 2163 2164 Hashtable props = subset.getProperties(); 2165 2166// String areaDirectoryKey = getKey(src, "POS"); 2167 String areaDirectoryKey = null; 2168 if (aid.getIsRelative()) { 2169 areaDirectoryKey = getKey(src, "POS"); 2170 } else { 2171 areaDirectoryKey = aid.getImageTime().toString(); 2172// areaDirectoryKey = getKey(src, "TIME"); 2173 } 2174 2175 // it only makes sense to set the following properties for things 2176 // coming from an ADDE server 2177 if (!isFromFile(aid)) { 2178 if (props.containsKey("PLACE")) { 2179 src = replaceKey(src, "PLACE", props.get("PLACE")); 2180 } 2181 if (props.containsKey("LATLON")) { 2182 src = replaceKey(src, "LINELE", "LATLON", props.get("LATLON")); 2183 } 2184 if (props.containsKey("LINELE")) { 2185 src = removeKey(src, "LATLON"); 2186 src = replaceKey(src, "LINELE", props.get("LINELE")); 2187 } 2188 if (props.containsKey("MAG")) { 2189 src = replaceKey(src, "MAG", props.get("MAG")); 2190 } 2191 } 2192 2193 aid.setSource(src); 2194 2195 SingleBandedImage result; 2196 result = (SingleBandedImage)getCache(src); 2197 if (result != null) { 2198 setDisplaySource(src, props); 2199 return result; 2200 } 2201 2202 // For now handle non ADDE URLs here 2203 try { 2204 AddeImageInfo aii = aid.getImageInfo(); 2205 AreaDirectory areaDir = null; 2206 try { 2207 if (aii != null) { 2208 logger.trace("imageinfo={}", aii.toString()); 2209 if (currentDirs != null) { 2210 int pos = Math.abs(aii.getDatasetPosition()); 2211 int band = 0; 2212 String bandString = aii.getBand(); 2213 if ((bandString != null) && !AddeURL.ALL.equals(bandString)) { 2214 band = Integer.parseInt(bandString); 2215 } 2216 // TODO: even though the band is non-zero we might only 2217 // get back one band 2218 band = 0; 2219 areaDir = currentDirs[currentDirs.length - pos - 1][band]; 2220 } else { 2221 // If its absolute time then just use the AD from the descriptor 2222 if ((aii.getStartDate() != null) || (aii.getEndDate() != null)) { 2223 areaDir = aid.getDirectory(); 2224 } else { 2225 } 2226 } 2227 } else { 2228 logger.trace("uh oh"); 2229 } 2230 } catch (Exception exc) { 2231 LogUtil.printMessage("error looking up area dir"); 2232 logger.error("error looking up area dir", exc); 2233 return null; 2234 } 2235 2236 if (areaDir == null) { 2237 areaDir = aid.getDirectory(); 2238 } 2239 2240 if (!getCacheDataToDisk()) { 2241 areaDir = null; 2242 } 2243 2244 if (!fromSequence || (aid.getIsRelative() && (currentDirs == null))) { 2245 areaDir = null; 2246 } 2247 2248 if (areaDir != null) { 2249 if (isFromFile(aid)) { 2250 if (rangeType == null) { 2251 result = AreaImageFlatField.createImmediate(aid, readLabel); 2252 } else { 2253 // Else, pass in the already created range type 2254 result = AreaImageFlatField.create(aid, areaDir, rangeType, readLabel); 2255 } 2256 } 2257 2258 } else { 2259 src = aid.getSource(); 2260 try { 2261 savePlace = this.laLoSel.getPlace(); 2262 saveLat = this.laLoSel.getLatitude(); 2263 saveLon = this.laLoSel.getLongitude(); 2264 saveNumLine = this.laLoSel.getNumLines(); 2265 saveNumEle = this.laLoSel.getNumEles(); 2266 saveLineMag = this.laLoSel.getLineMag(); 2267 saveEleMag = this.laLoSel.getElementMag(); 2268 } catch (Exception e) { 2269 logger.error("error reading from laLoSel", e); 2270 this.laLoSel.setPlace(savePlace); 2271 this.laLoSel.setLatitude(saveLat); 2272 this.laLoSel.setLongitude(saveLon); 2273 this.laLoSel.setNumLines(saveNumLine); 2274 this.laLoSel.setNumEles(saveNumEle); 2275 this.laLoSel.setLineMag(saveLineMag); 2276 this.laLoSel.setElementMag(saveEleMag); 2277 } 2278 2279 src = replaceKey(src, PLACE_KEY, savePlace); 2280 src = removeKey(src, LINELE_KEY); 2281 if (getKey(src, LATLON_KEY).length() != 0) { 2282 String latStr = Double.toString(saveLat); 2283 if (latStr.length() > 8) { 2284 latStr = latStr.substring(0,7); 2285 } 2286 String lonStr = Double.toString(saveLon); 2287 if (lonStr.length() > 9) { 2288 lonStr = lonStr.substring(0,8); 2289 } 2290 src = replaceKey(src, LATLON_KEY, latStr + ' ' + lonStr); 2291 } 2292 src = replaceKey(src, SIZE_KEY, saveNumLine + ' ' + saveNumEle); 2293 src = replaceKey(src, MAG_KEY, saveLineMag + ' ' + saveEleMag); 2294 } 2295 2296 // Relative bundles actually have the correct line/elem stored, at the time they were saved 2297 // This is likely to change over time, so we should not use it in these cases. 2298 logger.debug("fromBundle: " + fromBundle + ", isRelative: " + aid.getIsRelative()); 2299 if (fromBundle && aid.getIsRelative()) { 2300 src = removeKey(src, LINELE_KEY); 2301 } 2302 2303 AreaAdapter aa = new AreaAdapter(src, false); 2304 logger.trace("Getting a new aa={} for src=: {}", aa, src); 2305 areaDir = previewDir; 2306 result = aa.getImage(); 2307 2308 putCache(src, result); 2309 aid.setSource(src); 2310 iml.add(aid); 2311 setImageList(iml); 2312 setDisplaySource(src, props); 2313 return result; 2314 2315 } catch (java.io.IOException ioe) { 2316 throw new VisADException("Error creating AreaAdapter", ioe); 2317 } 2318 } 2319 2320 /** 2321 * Make a parameter name for the BandInfo 2322 * 2323 * @param bi the BandInfo in question 2324 * 2325 * @return a name for the parameter 2326 */ 2327 2328 private static String makeBandParam(BandInfo bi) { 2329 return new StringBuilder() 2330 .append(bi.getSensor()) 2331 .append("_Band") 2332 .append(bi.getBandNumber()) 2333 .append('_') 2334 .append(bi.getPreferredUnit()).toString(); 2335 } 2336 2337 private static String makeBandParam(AddeImageDescriptor descriptor) { 2338 AreaDirectory areaDir = descriptor.getDirectory(); 2339 if (areaDir == null) { 2340 throw new NullPointerException("No AREA directory!"); 2341 } 2342 return new StringBuilder() 2343 .append(areaDir.getSensorID()) 2344 .append("_Band") 2345 .append(areaDir.getBands()[0]) 2346 .append('_') 2347 .append(areaDir.getCalibrationType()).toString(); 2348 } 2349 2350 /** 2351 * Get a list of descriptors from the choice and subset 2352 * 2353 * @param dataChoice Data choice 2354 * @param subset subsetting info 2355 * 2356 * @return list of descriptors matching the selection 2357 */ 2358 2359 public List getDescriptors(DataChoice dataChoice, DataSelection subset) { 2360// logger.trace("choice={} subset props={} geo={}", new Object[] { dataChoice, subset.getProperties(), subset.getGeoSelection() }); 2361 int linRes = this.lineResolution; 2362 int eleRes = this.elementResolution; 2363 int newLinRes = linRes; 2364 int newEleRes = eleRes; 2365// List<TwoFacedObject> times = getTimesFromDataSelection(subset, dataChoice); 2366 List times = getTimesFromDataSelection(subset, dataChoice); 2367 boolean usingTimeDriver = ((subset != null) && (subset.getTimeDriverTimes() != null)); 2368 if (usingTimeDriver) { 2369 times = subset.getTimeDriverTimes(); 2370 } 2371 2372// if (dataChoice.getDataSelection() == null) { 2373// logger.trace("setting datasel!"); 2374// dataChoice.setDataSelection(subset); 2375// } 2376 if ((times == null) || times.isEmpty()) { 2377 times = imageTimes; 2378 } 2379// List<AddeImageDescriptor> descriptors = new ArrayList<AddeImageDescriptor>(times.size()); 2380 List descriptors = new ArrayList(); 2381 2382 if (usingTimeDriver) { 2383 if (imageList.isEmpty()) { 2384 return imageList; 2385 } 2386 AddeImageDescriptor aid = getDescriptor(imageList.get(0)); 2387 if (aid.getImageInfo() != null) { 2388 try { 2389 AddeImageInfo aii = 2390 (AddeImageInfo) aid.getImageInfo().clone(); 2391 // set the start and end dates 2392 Collections.sort(times); 2393 DateTime start = (DateTime) times.get(0); 2394 DateTime end = (DateTime) times.get(times.size() - 1); 2395 // In ADDE, you can't specify something like DAY=2011256 2011257 TIME=23:45:00 01:45:00 2396 // and expect that to be 2011256/23:45 to 2011257 01:45. Time ranges are on a per day 2397 // basis. So, we see if the starting time is a different day than the ending day and if so, 2398 // we set the start time to be 00Z on the first day an 23:59Z on the end day. 2399 // Even worse is that for archive datasets, you can't span multiple days. So make separate 2400 // requests for each day. 2401 String startDay = UtcDate.getYMD(start); 2402 String endDay = UtcDate.getYMD(end); 2403 List<String> days = new ArrayList<>(times.size()); 2404 if (!startDay.equals(endDay)) { 2405 days = getUniqueDayStrings(times); 2406 } else { 2407 days.add(startDay); 2408 } 2409 Map<DateTime, AreaDirectory> dateDir = new HashMap<>(days.size()); 2410 List<DateTime> dirTimes = new ArrayList<>(days.size() * 10); 2411 for (String day : days) { 2412 startDay = day + " 00:00:00"; 2413 endDay = day + " 23:59:59"; 2414 start = DateTime.createDateTime(startDay, 2415 DateTime.DEFAULT_TIME_FORMAT); 2416 end = UtcDate.createDateTime(endDay, 2417 DateTime.DEFAULT_TIME_FORMAT); 2418 aii.setStartDate(new Date((long) (start 2419 .getValue(CommonUnit.secondsSinceTheEpoch) * 1000))); 2420 aii.setEndDate(new Date((long) (end 2421 .getValue(CommonUnit.secondsSinceTheEpoch) * 1000))); 2422 // make the request for the times (AreaDirectoryList) 2423 aii.setRequestType(AddeURL.REQ_IMAGEDIR); 2424 AreaDirectoryList ad; 2425 try { // we may be asking for a date that doesn't exist 2426 ad = new AreaDirectoryList(aii.getURLString()); 2427 } catch (AreaFileException afe) { 2428 // If there's an error, we just ignore it. In the 2429 // end, the descriptor list will be empty if there is no 2430 // data for any of the days. 2431 continue; 2432 2433 // TODO: This is a hack because different servers return different 2434 // messages. AREA and GINI servers seem to have "no images" in the 2435 // exception message when there are no images. 2436 //String message = afe.getMessage().toLowerCase(); 2437 //if (message.indexOf("no images") >= 0 || 2438 // message.indexOf("error generating list of files") >= 0) { 2439 // continue; 2440 //} else { 2441 // throw afe; 2442 //} 2443 2444 } 2445 AreaDirectory[][] dirs = ad.getSortedDirs(); 2446 for (int d = 0; d < dirs.length; d++) { 2447 AreaDirectory dir = dirs[d][0]; 2448 DateTime dirTime = 2449 new DateTime(dir.getNominalTime()); 2450 dateDir.put(dirTime, dir); 2451 dirTimes.add(dirTime); 2452 } 2453 } 2454 List<DateTime> matchedTimes = selectTimesFromList(subset, 2455 dirTimes, times); 2456 for (DateTime dirTime : matchedTimes) { 2457 AreaDirectory dir = dateDir.get(dirTime); 2458 // shouldn't happen, but what the hey 2459 if (dir == null) { 2460 continue; 2461 } 2462 AddeImageInfo newaii = 2463 (AddeImageInfo) aid.getImageInfo().clone(); 2464 newaii.setRequestType(aii.REQ_IMAGEDATA); 2465 newaii.setStartDate(dir.getNominalTime()); 2466 newaii.setEndDate(dir.getNominalTime()); 2467 setBandInfo(dataChoice, newaii); 2468 AddeImageDescriptor newaid = 2469 new AddeImageDescriptor(dir, 2470 newaii.getURLString(), newaii); 2471 newaid.setIsRelative(false); 2472 descriptors.add(newaid); 2473 } 2474 } catch (CloneNotSupportedException cnse) { 2475 logger.error("Unable to clone AddeImageInfo (aii)", cnse); 2476 } catch (VisADException vader) { 2477 logger.error("Unable to get date values", vader); 2478 } catch (AreaFileException afe) { 2479 logger.error("Unable to make ADDE request", afe); 2480 } catch (Exception excp) { 2481 logger.error("Exception occurred while handling time driver", excp); 2482 } 2483 // we do this so save data local will work. However, if 2484 // this then gets set to be the time driver, it would not 2485 // necessarily be correct 2486 imageList = descriptors; 2487 return descriptors; 2488 } else if (imageList != null) { 2489 return imageList; 2490 } 2491 } 2492 2493 int choiceBandNum = ((BandInfo) dataChoice.getId()).getBandNumber(); 2494 int choiceSensorId = ((BandInfo) dataChoice.getId()).getSensor(); 2495 String choicePrefUnit = ((BandInfo) dataChoice.getId()).getPreferredUnit(); 2496 for (Iterator iter = times.iterator(); iter.hasNext(); ) { 2497 Object time = iter.next(); 2498 AddeImageDescriptor found = null; 2499 AddeImageDescriptor foundTimeMatch = null; 2500 if (saveImageList.isEmpty()) { 2501 saveImageList = getImageList(); 2502 } 2503 for (Iterator iter2 = saveImageList.iterator(); iter2.hasNext(); ) { 2504 AddeImageDescriptor aid = getDescriptor(iter2.next()); 2505 if (aid != null) { 2506 if (aid.getIsRelative()) { 2507 Object id; 2508 if (time instanceof TwoFacedObject) { 2509 id = ((TwoFacedObject)time).getId(); 2510 } else { 2511 id = time; 2512 } 2513 if ((id instanceof Integer) && ((Integer)id).intValue() == aid.getRelativeIndex()) { 2514 found = aid; 2515 break; 2516 } 2517 } else { 2518 int aidBand = aid.getDirectory().getBands()[0]; 2519 int aidSensorId = aid.getDirectory().getSensorID(); 2520 String calType = aid.getDirectory().getCalibrationType(); 2521 if (foundTimeMatch == null && aid.getImageTime().equals(time)) { 2522 logger.trace("found time match {}", time); 2523 foundTimeMatch = aid; 2524 } 2525 if (aid.getImageTime().equals(time) && choiceBandNum == aidBand && choiceSensorId == aidSensorId && choicePrefUnit.equals(calType)) { 2526 // the problem is here! 2527 logger.trace("found aid={} src={}", makeBandParam(aid), aid.getSource()); 2528 logger.trace("target info: param={}", dataChoice.getName()); 2529 found = aid; 2530 break; 2531 } 2532 } 2533 } 2534 } 2535 2536 if (found == null && foundTimeMatch != null) { 2537 logger.trace("good enough!?"); 2538 found = foundTimeMatch; 2539 } 2540 2541 if (found != null) { 2542 try { 2543 AddeImageDescriptor desc = new AddeImageDescriptor(found); 2544 // Sometimes we might have a null imageinfo 2545 if (desc.getImageInfo() != null) { 2546 AddeImageInfo aii = 2547 (AddeImageInfo) desc.getImageInfo().clone(); 2548 BandInfo bi = (BandInfo) dataChoice.getId(); 2549 List<BandInfo> bandInfos = 2550 (List<BandInfo>) getProperty(PROP_BANDINFO, (Object) null); 2551 boolean hasBand = true; 2552 // If this data source has been changed after we have create a display 2553 // then the possibility exists that the bandinfo contained by the incoming 2554 // data choice might not be valid. If it isn't then default to the first 2555 // one in the list 2556 if (bandInfos != null) { 2557 hasBand = bandInfos.contains(bi); 2558 if(!hasBand) { 2559 } 2560 if(!hasBand && bandInfos.size() > 0) { 2561 bi = bandInfos.get(0); 2562 } else { 2563 //Not sure what to do here. 2564 } 2565 } 2566 aii.setBand("" + bi.getBandNumber()); 2567 aii.setPlaceValue("ULEFT"); 2568 2569 try { 2570 AddeImageDescriptor newAid = new AddeImageDescriptor(aii.getURLString()); 2571 AreaDirectory newAd = newAid.getDirectory(); 2572 newLinRes = newAd.getValue(AreaFile.AD_LINERES); 2573 newEleRes = newAd.getValue(AreaFile.AD_ELEMRES); 2574 } catch (Exception e) { 2575 logger.error("resetting resolution", e); 2576 } 2577 2578 double[][] projCoords = new double[2][2]; 2579 try { 2580 AreaDirectory ad = desc.getDirectory(); 2581 double lin = (double) ad.getValue(AreaFile.AD_STLINE); 2582 double ele = (double) ad.getValue(AreaFile.AD_STELEM); 2583 aii.setLocateKey("LINELE"); 2584 aii.setLocateValue((int)lin + " " + (int)ele); 2585 projCoords[0][0] = lin; 2586 projCoords[1][0] = ele; 2587 lin += (double)ad.getValue(AreaFile.AD_NUMLINES); 2588 ele += (double)ad.getValue(AreaFile.AD_NUMELEMS); 2589 projCoords[0][1] = lin; 2590 projCoords[1][1] = ele; 2591 } catch (Exception e) { 2592 logger.error("problem with adjusting projCoords?", e); 2593 return descriptors; 2594 } 2595 int lins = Math.abs((int)(projCoords[1][1] - projCoords[1][0])); 2596 int eles = Math.abs((int)(projCoords[0][1] - projCoords[0][0])); 2597 lins = lins*linRes/newLinRes; 2598 if (this.lineMag > 0) { 2599 lins *= this.lineMag; 2600 } else { 2601 lins /= -this.lineMag; 2602 } 2603 2604 eles = eles*eleRes/newEleRes; 2605 2606 if (elementMag > 0) { 2607 eles *= elementMag; 2608 } else { 2609 eles /= -elementMag; 2610 } 2611 2612 aii.setLines(lins); 2613 aii.setElements(eles); 2614 desc.setImageInfo(aii); 2615 desc.setSource(aii.getURLString()); 2616 } 2617 descriptors.add(desc); 2618 } catch (CloneNotSupportedException cnse) {} 2619 } 2620 } 2621 return descriptors; 2622 } 2623 2624 /** 2625 * Get the subset of the composite based on the selection 2626 * 2627 * @param choice composite choice 2628 * @param subset time selection 2629 * 2630 * @return subset list 2631 */ 2632 2633 private List getChoicesFromSubset(CompositeDataChoice choice, 2634 DataSelection subset) { 2635 List choices = choice.getDataChoices(); 2636 if (subset == null) { 2637 return choices; 2638 } 2639 List times = subset.getTimes(); 2640 if (times == null) { 2641 return choices; 2642 } 2643 times = TwoFacedObject.getIdList(times); 2644 List subChoices = new ArrayList(); 2645 Object firstTime = times.get(0); 2646 if (firstTime instanceof Integer) { 2647 for (Iterator iter = times.iterator(); iter.hasNext(); ) { 2648 subChoices.add( 2649 choices.get(((Integer) iter.next()).intValue())); 2650 } 2651 } else { // TODO: what if they are DateTimes? 2652 subChoices.addAll(choices); 2653 } 2654 return subChoices; 2655 } 2656 2657 private List<AreaDirectory> getPreviewDirectories(final AddeImageDescriptor imageDescriptor) { 2658 List<AreaDirectory> directories = new ArrayList<AreaDirectory>(imageTimes.size()); 2659 2660 return directories; 2661 } 2662 2663// private AreaDirectory getPreviewDirectory(AddeImageDescriptor aid) { 2664// AreaDirectory directory = aid.getDirectory(); 2665// AddeImageDescriptor descriptor = null; 2666// int times = imageTimes.size(); 2667// if (times == 1) { 2668// logger.trace("only looking for a single time; returning AreaDirectory grabbed from incoming AddeImageDescriptor. directory={}", directory); 2669// return directory; 2670// } 2671// String src = aid.getSource(); 2672// logger.trace("URL for incoming AddeImageDescriptor: {}", src); 2673// src = removeKey(src, LATLON_KEY); 2674// src = removeKey(src, LINELE_KEY); 2675// src = removeKey(src, PLACE_KEY); 2676// src = removeKey(src, SIZE_KEY); 2677// src = removeKey(src, UNIT_KEY); 2678// src = removeKey(src, MAG_KEY); 2679// src = removeKey(src, SPAC_KEY); 2680// src = removeKey(src, NAV_KEY); 2681// src = removeKey(src, AUX_KEY); 2682// src = removeKey(src, DOC_KEY); 2683// 2684// int maxLine = 0; 2685// int maxEle = 0; 2686// int imageSize = 0; 2687// src = src.replace("imagedata", "imagedir"); 2688// boolean isRelative = aid.getIsRelative(); 2689// for (int i=0; i<times; i++) { 2690// if (isRelative) { 2691// src = replaceKey(src, "POS", Integer.valueOf(i).toString()); 2692// } else { 2693// DateTime dt = (DateTime)imageTimes.get(i); 2694// String timeStr = dt.timeString(); 2695// timeStr = timeStr.replace("Z", " "); 2696// src = removeKey(src, "POS"); 2697// src = replaceKey(src, "TIME", timeStr + timeStr + "I"); 2698// } 2699// try { 2700// logger.trace("attempting to create AreaDirectoryList using src={}", src); 2701// AreaDirectoryList dirList = new AreaDirectoryList(src); 2702// List ad = dirList.getDirs(); 2703// AreaDirectory areaDir = (AreaDirectory)ad.get(0); 2704// logger.trace("created AreaDirectory: {}", areaDir); 2705// int lines = areaDir.getLines(); 2706// int eles = areaDir.getElements(); 2707// if (imageSize < lines*eles) { 2708// imageSize = lines * eles; 2709// maxLine = lines; 2710// maxEle = eles; 2711// directory = areaDir; 2712// descriptor = new AddeImageDescriptor(src); 2713// } 2714// } catch (Exception e) { 2715// logger.error("problem when dealing with AREA directory", e); 2716// } 2717// } 2718// logger.trace("returning AreaDirectory: {}", directory); 2719// logger.trace("could return AddeImageDescriptor:\nisRelative={}\nrelativeIndex={}\ntime={}\ndirectory={}\n", new Object[] { descriptor.getIsRelative(), descriptor.getRelativeIndex(), descriptor.getImageTime(), descriptor.getDirectory()}); 2720// return directory; 2721// } 2722 2723 private AddeImageDescriptor getPreviewDirectory(AddeImageDescriptor aid, DataChoice dataChoice) { 2724 2725 // Used to detect domain shifts for sectors like ABI MESO 2726 float domainCenterLat = -1.0f; 2727 float domainCenterLon = -1.0f; 2728 2729 AreaDirectory directory = aid.getDirectory(); 2730 AddeImageDescriptor descriptor = null; 2731 int times = imageTimes.size(); 2732 if (times == 1) { 2733 logger.trace("only looking for a single time; returning AreaDirectory grabbed from incoming AddeImageDescriptor. directory={}", directory); 2734// return directory; 2735 return aid; 2736 } 2737 2738 String src = aid.getSource(); 2739 logger.trace("URL for incoming AddeImageDescriptor: {}", src); 2740 2741 src = removeKey(src, LATLON_KEY); 2742 src = removeKey(src, LINELE_KEY); 2743 src = removeKey(src, PLACE_KEY); 2744 src = removeKey(src, SIZE_KEY); 2745 src = removeKey(src, UNIT_KEY); 2746 src = removeKey(src, MAG_KEY); 2747 src = removeKey(src, SPAC_KEY); 2748 src = removeKey(src, NAV_KEY); 2749 src = removeKey(src, AUX_KEY); 2750 src = removeKey(src, DOC_KEY); 2751 2752 int maxLine = 0; 2753 int maxEle = 0; 2754 int imageSize = 0; 2755 int prevSize = 0; 2756 src = src.replace("imagedata", "imagedir"); 2757 boolean isRelative = aid.getIsRelative(); 2758 2759 // Note the index if we detect a domain shift, we will cut the loop off there 2760 int domainShiftIndex = 0; 2761 2762 List<String> previewUrls = new ArrayList<String>(times); 2763 2764 if (isRelative) { 2765 2766 // TJJ Mar 2015 - (1891, R14) 2767 // Iterate through list to determine relative position different 2768 // if the objects are VisAD DateTime instead of TwoFacedObject 2769 2770 boolean isTwoFaced = false; 2771 List<?> tmpList = getAllDateTimes(); 2772 if ((tmpList != null) && (! tmpList.isEmpty())) { 2773 Object firstItem = tmpList.get(0); 2774 if (firstItem instanceof TwoFacedObject) isTwoFaced = true; 2775 } 2776 2777 int maxIndex; 2778 if (isTwoFaced) { 2779 maxIndex = Integer.MIN_VALUE; 2780 for (TwoFacedObject tfo : (List<TwoFacedObject>) getAllDateTimes()) { 2781 int relativeIndex = ((Integer) tfo.getId()).intValue(); 2782 if (relativeIndex > maxIndex) { 2783 maxIndex = relativeIndex; 2784 } 2785 } 2786 } else { 2787 maxIndex = Integer.MIN_VALUE; 2788 int relativeIndex = 0; 2789 double maxTime = Double.MIN_VALUE; 2790 for (DateTime dt : (List<DateTime>) getAllDateTimes()) { 2791 double d = dt.getValue(); 2792 if (d > maxTime) { 2793 maxIndex = relativeIndex; 2794 maxTime = d; 2795 } 2796 relativeIndex++; 2797 } 2798 } 2799 2800// TwoFacedObject tfo = (TwoFacedObject)this.getAllDateTimes().get(0); 2801 // negate maxIndex so we can get things like POS=0 or POS=-4 2802 maxIndex = 0 - maxIndex; 2803 logger.trace("using maxIndex={}", maxIndex); 2804 src = replaceKey(src, "POS", Integer.toString(maxIndex)); 2805 previewUrls.add(src); 2806 2807 } else { 2808 for (int i = 0; i < times; i++) { 2809 DateTime dt = (DateTime)imageTimes.get(i); 2810 String timeStr = dt.timeString(); 2811 timeStr = timeStr.replace("Z", " "); 2812 src = removeKey(src, "POS"); 2813 src = replaceKey(src, "TIME", timeStr + timeStr + 'I'); 2814 logger.trace("using time value: ", timeStr + timeStr + 'I'); 2815 logger.trace("added absolute time preview url: {}", src); 2816 previewUrls.add(src); 2817 } 2818 } 2819 2820 if (! isRelative && (previewUrls.size() == 1)) { 2821 logger.trace("only a single previewUrl; returning '{}'", previewUrls.get(0)); 2822 return new AddeImageDescriptor(previewUrls.get(0)); 2823 } else { 2824 logger.trace("preparing to examine previewUrls={}", previewUrls); 2825 } 2826 2827 // TJJ Aug 2020 2828 // Look for GEO-based domain shifts (e.g. MESO sector moves mid-loop) 2829 // The first image checked will initialize domain center lat. After 2830 // that, anything different is a domain shift 2831 2832 if (isABISensor) { 2833 2834 int urlIdx = 0; 2835 for (String urlStr : previewUrls) { 2836 2837 AddeImageDescriptor tmpAID = new AddeImageDescriptor(urlStr); 2838 AreaDirectory tmpAD = tmpAID.getDirectory(); 2839 2840 if (domainCenterLat == -1.0f) { 2841 domainCenterLat = (float) tmpAD.getCenterLatitude(); 2842 } else { 2843 if ((float) tmpAD.getCenterLatitude() != domainCenterLat) { 2844 domainCenterLat = (float) tmpAD.getCenterLatitude(); 2845 logger.info("Domain shift, set LAT to: " + domainCenterLat); 2846 domainShiftDetected = true; 2847 domainShiftIndex = urlIdx; 2848 } 2849 } 2850 // The first image checked will initialize domain center lon 2851 if (domainCenterLon == -1.0f) { 2852 domainCenterLon = (float) tmpAD.getCenterLongitude(); 2853 } else { 2854 if ((float) tmpAD.getCenterLongitude() != domainCenterLon) { 2855 domainCenterLon = (float) tmpAD.getCenterLongitude(); 2856 logger.info("Domain shift, set LON to: " + domainCenterLon); 2857 domainShiftDetected = true; 2858 domainShiftIndex = urlIdx; 2859 } 2860 } 2861 2862 urlIdx++; 2863 2864 } 2865 2866 } 2867 2868 try { 2869 2870 // TJJ Nov 2017 2871 // As an interim speedup, for Inq #2496, we are going to binary search the list 2872 // intstead of iterating through every single URL to make large loop times 2873 // (e.g. 50 GOES-16 MESO images) more tolerable. 2874 2875 if (isGeoSensor && (previewUrls.size() > 1)) { 2876 2877 int loIdx = 0; 2878 int hiIdx = previewUrls.size() - 1; 2879 boolean directionInc = true; 2880 boolean sizeMatch = false; 2881 int iterations = 0; 2882 2883 while (! sizeMatch) { 2884 2885 String previewUrl = null; 2886 if (directionInc) { 2887 previewUrl = previewUrls.get(loIdx); 2888 loIdx++; 2889 directionInc = false; 2890 } else { 2891 previewUrl = previewUrls.get(hiIdx); 2892 hiIdx--; 2893 directionInc = true; 2894 } 2895 2896 // Sanity check - if we get to the middle, we just quit and use what we found 2897 if ((loIdx > hiIdx) && (! isRelative)) break; 2898 2899 logger.trace("attempting to create AreaDirectoryList using previewUrl={}", previewUrl); 2900 AreaDirectoryList directoryList = new AreaDirectoryList(previewUrl); 2901 logger.trace("created directoryList! size={}\n{}", directoryList.getDirs().size(), directoryList); 2902 List<AreaDirectory> areaDirectories = (List<AreaDirectory>) directoryList.getDirs(); 2903 2904 for (int i = 0; i < areaDirectories.size(); i++) { 2905 iterations++; 2906 AreaDirectory areaDirectory = areaDirectories.get(i); 2907 String pos = Integer.toString(0 - i); 2908 int lines = areaDirectory.getLines(); 2909 int elements = areaDirectory.getElements(); 2910 int currentDimensions = lines * elements; 2911 logger.trace("image pos={} lines={} elements={} lat={} lon={} startTime='{}' nominalTime='{}' currentDimensions={} areaDirectory={}", new Object[] { pos, lines, elements, areaDirectory.getCenterLatitude(), areaDirectory.getCenterLongitude(), areaDirectory.getStartTime(), areaDirectory.getNominalTime(), currentDimensions, areaDirectory }); 2912 String key = null; 2913 if (isRelative) { 2914 key = pos; 2915 } else { 2916 try { 2917 DateTime reformatted = new DateTime(areaDirectory.getNominalTime()); 2918 key = reformatted.toString(); 2919 } catch (VisADException e) { 2920 logger.error("could not reformat time string='"+areaDirectory.getNominalTime().toString()+"'", e); 2921 key = areaDirectory.getNominalTime().toString(); 2922 } 2923 } 2924 requestIdToDirectory.put(key, areaDirectory); 2925 2926 if (imageSize < currentDimensions) { 2927 2928 imageSize = currentDimensions; 2929 maxLine = lines; 2930 maxEle = elements; 2931 directory = areaDirectory; 2932 // TODO(jon): should be grabbing coord sys from chooser setting (HOW TO DO THAT!?) 2933 String latlonString = areaDirectory.getCenterLatitude() + " " + areaDirectory.getCenterLongitude() + " E"; 2934 String largestPreviewUrl = previewUrl.replace("imagedir", "imagedata"); 2935 largestPreviewUrl = replaceKey(largestPreviewUrl, "PLACE", "CENTER"); 2936 largestPreviewUrl = replaceKey(largestPreviewUrl, "LATLON", latlonString); 2937 Hashtable dataSourceProperties = this.getProperties(); 2938 if (dataSourceProperties.containsKey("navigation")) { 2939 largestPreviewUrl = replaceKey(largestPreviewUrl, "NAV", dataSourceProperties.get("navigation")); 2940 } 2941 2942 if (isRelative) { 2943 largestPreviewUrl = replaceKey(largestPreviewUrl, "POS", pos); 2944 } else { 2945 logger.trace("need to set DAY and TIME keywords for absolute times!"); 2946 } 2947 2948 logger.trace("found new max size! old={} new={} url={}", new Object[] { imageSize, currentDimensions, largestPreviewUrl }); 2949 descriptor = new AddeImageDescriptor(areaDirectory, largestPreviewUrl); 2950 2951 } 2952 2953 if (prevSize == currentDimensions) { 2954 logger.debug("Exiting Preview URL loop after " + iterations + " iterations..."); 2955 sizeMatch = true; 2956 } 2957 prevSize = currentDimensions; 2958 } 2959 } 2960 } else { 2961 2962 // Old way - go through all preview URLs looking for largest geographic coverage 2963 2964 for (String previewUrl : previewUrls) { 2965 2966 logger.trace("attempting to create AreaDirectoryList using previewUrl={}", previewUrl); 2967 AreaDirectoryList directoryList = new AreaDirectoryList(previewUrl); 2968 logger.trace("created directoryList! size={}\n{}", directoryList.getDirs().size(), directoryList); 2969 List<AreaDirectory> areaDirectories = (List<AreaDirectory>) directoryList.getDirs(); 2970 2971 for (int i = 0; i < areaDirectories.size(); i++) { 2972 2973 AreaDirectory areaDirectory = areaDirectories.get(i); 2974 String pos = Integer.toString(0 - i); 2975 int lines = areaDirectory.getLines(); 2976 int elements = areaDirectory.getElements(); 2977 int currentDimensions = lines * elements; 2978 logger.trace("image pos={} lines={} elements={} lat={} lon={} startTime='{}' nominalTime='{}' currentDimensions={} areaDirectory={}", new Object[] { pos, lines, elements, areaDirectory.getCenterLatitude(), areaDirectory.getCenterLongitude(), areaDirectory.getStartTime(), areaDirectory.getNominalTime(), currentDimensions, areaDirectory }); 2979 String key = null; 2980 if (isRelative) { 2981 key = pos; 2982 } else { 2983 try { 2984 DateTime reformatted = new DateTime(areaDirectory.getNominalTime()); 2985 key = reformatted.toString(); 2986 } catch (VisADException e) { 2987 logger.error("could not reformat time string='"+areaDirectory.getNominalTime().toString()+"'", e); 2988 key = areaDirectory.getNominalTime().toString(); 2989 } 2990 } 2991 requestIdToDirectory.put(key, areaDirectory); 2992 if (imageSize < currentDimensions) { 2993 2994 imageSize = currentDimensions; 2995 maxLine = lines; 2996 maxEle = elements; 2997 directory = areaDirectory; 2998 // TODO(jon): should be grabbing coord sys from chooser setting (HOW TO DO THAT!?) 2999 String latlonString = areaDirectory.getCenterLatitude() + " " + areaDirectory.getCenterLongitude() + " E"; 3000 String largestPreviewUrl = previewUrl.replace("imagedir", "imagedata"); 3001 largestPreviewUrl = replaceKey(largestPreviewUrl, "PLACE", "CENTER"); 3002 largestPreviewUrl = replaceKey(largestPreviewUrl, "LATLON", latlonString); 3003 Hashtable dataSourceProperties = this.getProperties(); 3004 if (dataSourceProperties.containsKey("navigation")) { 3005 largestPreviewUrl = replaceKey(largestPreviewUrl, "NAV", dataSourceProperties.get("navigation")); 3006 } 3007 3008 if (isRelative) { 3009 largestPreviewUrl = replaceKey(largestPreviewUrl, "POS", pos); 3010 } else { 3011 logger.trace("need to set DAY and TIME keywords for absolute times!"); 3012 } 3013 3014 logger.trace("found new max size! old={} new={} url={}", new Object[] { imageSize, currentDimensions, largestPreviewUrl }); 3015 descriptor = new AddeImageDescriptor(areaDirectory, largestPreviewUrl); 3016 3017 } 3018 } 3019 } 3020 } 3021 } catch (AreaFileException areaException) { 3022 logger.error("problem when dealing with AREA directory", areaException); 3023 } 3024// for (int i = 0; i < times; i++) { 3025// if (isRelative) { 3026// src = replaceKey(src, "POS", Integer.valueOf(i).toString()); 3027// } else { 3028// DateTime dt = (DateTime)imageTimes.get(i); 3029// String timeStr = dt.timeString(); 3030// timeStr = timeStr.replace("Z", " "); 3031// src = removeKey(src, "POS"); 3032// src = replaceKey(src, "TIME", timeStr + timeStr + "I"); 3033// } 3034// // don't forget to NOT negate POS=0 3035// try { 3036// logger.trace("attempting to create AreaDirectoryList using src={}", src); 3037// AreaDirectoryList dirList = new AreaDirectoryList(src); 3038// List ad = dirList.getDirs(); 3039// AreaDirectory areaDir = (AreaDirectory)ad.get(0); 3040// logger.trace("created AreaDirectory: {}", areaDir); 3041// int lines = areaDir.getLines(); 3042// int eles = areaDir.getElements(); 3043// logger.trace("image lines={} eles={} for src={}", new Object[] { lines, eles, src }); 3044// if (imageSize < lines*eles) { 3045// logger.trace("found new max size! old={} new={}", imageSize, lines*eles); 3046// imageSize = lines * eles; 3047// maxLine = lines; 3048// maxEle = eles; 3049// directory = areaDir; 3050// descriptor = new AddeImageDescriptor(src); 3051// } 3052// } catch (Exception e) { 3053// logger.error("problem when dealing with AREA directory", e); 3054// } 3055// } 3056// 3057 3058 // If domain shift was detected, keep only the pre-shift times for derived data 3059 logger.info("domainShiftIndex: " + domainShiftIndex); 3060 3061 logger.trace("returning AreaDirectory: {}", directory); 3062// logger.trace("could return AddeImageDescriptor:\nisRelative={}\nrelativeIndex={}\ntime={}\ndirectory={}\n", new Object[] { descriptor.getIsRelative(), descriptor.getRelativeIndex(), descriptor.getImageTime(), descriptor.getDirectory()}); 3063 return descriptor; 3064 } 3065 3066 private String getServer(String urlString) { 3067 int ix = urlString.indexOf("//") + 2; 3068 String temp = urlString.substring(ix); 3069 ix = temp.indexOf("/"); 3070 String retStr = temp.substring(0, ix); 3071 return retStr; 3072 } 3073 3074 public void setDisplaySource(String src, Hashtable props) { 3075 if (!props.isEmpty()) { 3076 Enumeration propEnum = props.keys(); 3077 for (int i=0; propEnum.hasMoreElements(); i++) { 3078 String key = propEnum.nextElement().toString(); 3079 Object val = props.get(key); 3080 if (getKey(src, key).length() != 0) { 3081 src = replaceKey(src, key, val); 3082 } 3083 } 3084 } 3085 this.displaySource = src; 3086 String unit = getKey(src, UNIT_KEY); 3087 if (unit.length() != 0) { 3088 sourceProps.put(UNIT_KEY.toUpperCase(), unit); 3089 } 3090 } 3091 3092 public String getDisplaySource() { 3093 return this.displaySource; 3094 } 3095 3096 3097 private float[] getLineEleResolution(AreaDirectory ad) { 3098 logger.trace("ad: {} sensor: {}", ad, ad.getSensorID()); 3099 float[] res = {(float)1.0, (float)1.0}; 3100 int sensor = ad.getSensorID(); 3101 List lines = null; 3102 try { 3103 String buff = getUrl(); 3104 3105 lines = readTextLines(buff); 3106 if (lines == null) { 3107 return res; 3108 } 3109 3110 int gotit = -1; 3111 String[] cards = StringUtil.listToStringArray(lines); 3112 logger.trace("cards: {}", cards); 3113 3114 for (int i = 0; i < cards.length; i++) { 3115 if ( ! cards[i].startsWith("Sat ")) continue; 3116 StringTokenizer st = new StringTokenizer(cards[i]," "); 3117 String temp = st.nextToken(); // throw away the key 3118 int m = st.countTokens(); 3119 for (int k = 0; k < m; k++) { 3120 int ss = Integer.parseInt(st.nextToken().trim()); 3121 if (ss == sensor) { 3122 gotit = i; 3123 break; 3124 } 3125 } 3126 3127 if (gotit != -1) { 3128 break; 3129 } 3130 } 3131 3132 if (gotit == -1) { 3133 return res; 3134 } 3135 3136 int gotSrc = -1; 3137 for (int i = gotit; i < cards.length; i++) { 3138 if (cards[i].startsWith("EndSat")) { 3139 return res; 3140 } 3141 if (!cards[i].startsWith("B") ) { 3142 continue; 3143 } 3144 StringTokenizer tok = new StringTokenizer(cards[i]); 3145 String str = tok.nextToken(); 3146 str = tok.nextToken(); 3147 Float flt = Float.valueOf(str); 3148 res[0] = flt.floatValue(); 3149 str = tok.nextToken(); 3150 flt = Float.valueOf(str); 3151 res[1] = flt.floatValue(); 3152 return res; 3153 } 3154 } catch (Exception e) { 3155 logger.error("problem getting the line+element rez", e); 3156 } 3157 return res; 3158 } 3159 3160 /** 3161 * Read the adde text url and return the lines of text. 3162 * If unsuccessful return null. 3163 * 3164 * @param url adde url to a text file 3165 * 3166 * @return List of lines or {@code null} if in error. 3167 */ 3168 3169 protected List readTextLines(String url) { 3170 AddeTextReader reader = new AddeTextReader(url); 3171 List lines = null; 3172 if ("OK".equals(reader.getStatus())) { 3173 lines = reader.getLinesOfText(); 3174 } 3175 return lines; 3176 } 3177 3178 /** 3179 * Create the first part of the ADDE request URL 3180 * 3181 * @return ADDE URL prefix 3182 */ 3183 3184 protected String getUrl() { 3185 String str = source; 3186 str = str.replaceFirst("imagedata", "text"); 3187 int indx = str.indexOf("VERSION"); 3188 str = str.substring(0, indx); 3189 str = str.concat("file=SATBAND"); 3190 return str; 3191 } 3192 3193 public Hashtable getSourceProps() { 3194 return this.sourceProps; 3195 } 3196 3197 public void setSourceProps(Hashtable sourceProps) { 3198 this.sourceProps = sourceProps; 3199 } 3200 3201 public String getChoiceName() { 3202 return this.choiceName; 3203 } 3204 3205 public void setChoiceName(String choiceName) { 3206 this.choiceName = choiceName; 3207 } 3208 3209 public String getSavePlace() { 3210 return this.savePlace; 3211 } 3212 3213 public void setSavePlace(String savePlace) { 3214 this.savePlace = savePlace; 3215 } 3216 3217 public double getSaveLat() { 3218 return this.saveLat; 3219 } 3220 3221 public void setSaveLat(double saveLat) { 3222 this.saveLat = saveLat; 3223 } 3224 3225 public double getSaveLon() { 3226 return this.saveLon; 3227 } 3228 3229 public void setSaveLon(double saveLon) { 3230 this.saveLon = saveLon; 3231 } 3232 3233 public int getSaveNumLine() { 3234 return this.saveNumLine; 3235 } 3236 3237 public void setSaveNumLine(int saveNumLine) { 3238 this.saveNumLine = saveNumLine; 3239 } 3240 3241 public int getSaveNumEle() { 3242 return this.saveNumEle; 3243 } 3244 3245 public void setSaveNumEle(int saveNumEle) { 3246 this.saveNumEle = saveNumEle; 3247 } 3248 3249 public int getSaveLineMag() { 3250 return this.saveLineMag; 3251 } 3252 3253 public void setSaveLineMag(int saveLineMag) { 3254 this.saveLineMag = saveLineMag; 3255 } 3256 3257 public int getSaveEleMag() { 3258 return this.saveEleMag; 3259 } 3260 3261 public void setSaveEleMag(int saveEleMag) { 3262 this.saveEleMag = saveEleMag; 3263 } 3264 3265 public String getSource() { 3266 return this.source; 3267 } 3268 3269 public void setSource(String source) { 3270 this.source = source; 3271 } 3272 3273 public boolean getShowPreview() { 3274 return this.showPreview; 3275 } 3276 3277 public void setShowPreview(boolean showPreview) { 3278 this.showPreview = showPreview; 3279 } 3280 3281 public boolean getSaveShowPreview() { 3282 return this.saveShowPreview; 3283 } 3284 3285 public void setSaveShowPreview(boolean saveShowPreview) { 3286 this.saveShowPreview = saveShowPreview; 3287 } 3288 3289 private void getSaveComponents() { 3290 saveCoordType = this.laLoSel.getCoordinateType(); 3291 savePlace = this.laLoSel.getPlace(); 3292 if (saveCoordType.equals(this.laLoSel.getLatLonType())) { 3293 saveLat = this.laLoSel.getLatitude(); 3294 saveLon = this.laLoSel.getLongitude(); 3295 } 3296 saveNumLine = this.laLoSel.getNumLines(); 3297 saveNumEle = this.laLoSel.getNumEles(); 3298 saveLineMag = this.laLoSel.getLineMag(); 3299 saveEleMag = this.laLoSel.getElementMag(); 3300 } 3301 3302 /** 3303 * Return the list of times held by the DataSelection member. 3304 * 3305 * @return DataSelection times 3306 */ 3307 3308 public List getDateTimeSelection() { 3309// return super.getDateTimeSelection(); 3310 DataSelection s = getDataSelection(); 3311 if (s == null) { 3312 logger.trace("oh no getDataSelection is null :("); 3313 return null; 3314 } else { 3315 return s.getTimes(); 3316 } 3317 } 3318 3319 /** 3320 * Set the list of selected times for this data source. This is used 3321 * for XML persistence. 3322 * 3323 * @param selectedTimes List of selected times 3324 */ 3325 3326 public void setDateTimeSelection(List selectedTimes) { 3327// //Check to see if we need to convert the absolute times into an index list. 3328// if (holdsDateTimes(selectedTimes) && (timesList != null)) { 3329// selectedTimes = Misc.getIndexList(selectedTimes, 3330// getAllDateTimes()); 3331// } 3332// getDataSelection().setTimes(selectedTimes); 3333 super.setDateTimeSelection(selectedTimes); 3334 List selected = getDateTimeSelection(); 3335 logger.trace("incoming: {} result: {}", selectedTimes, selected); 3336 } 3337 3338 protected boolean canDoProgressiveResolution() { 3339 return false; 3340 } 3341 3342 public boolean getIsProgressiveResolution() { 3343 return false; 3344 } 3345 3346 public void setIsProgressiveResolution(boolean isPG) { 3347 3348 } 3349 3350 public boolean getMatchDisplayRegion() { 3351 return false; 3352 } 3353 3354 public static class BundlePreviewSelection extends DataSelectionComponent { 3355 final String label; 3356 public BundlePreviewSelection(final String label) { 3357 super(label); 3358 this.label = label; 3359 } 3360 3361 @Override protected JComponent doMakeContents() { 3362 // TODO Auto-generated method stub 3363 JPanel panel = new JPanel(); 3364 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 3365 JLabel label1 = new JLabel("Area coverage has been defined by the data bundle;"); 3366 JLabel label2 = new JLabel("further subsetting is not currently supported."); 3367 label1.setAlignmentX(Component.CENTER_ALIGNMENT); 3368 label2.setAlignmentX(Container.CENTER_ALIGNMENT); 3369 panel.add(label1); 3370 panel.add(label2); 3371 return panel; 3372 } 3373 3374 @Override public void applyToDataSelection(DataSelection dataSelection) { 3375 } 3376 3377 /** 3378 * Overridden to disable these dummy tabs from showing up in properties 3379 * dialog. 3380 */ 3381 @Override public boolean getShowInControlProperties() { 3382 return false; 3383 } 3384 } 3385}