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