001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.data.hydra;
030
031import java.awt.BorderLayout;
032import java.awt.FlowLayout;
033import java.awt.geom.Rectangle2D;
034import java.io.File;
035import java.rmi.RemoteException;
036import java.util.ArrayList;
037import java.util.Collections;
038import java.util.Enumeration;
039import java.util.HashMap;
040import java.util.Hashtable;
041import java.util.LinkedHashSet;
042import java.util.List;
043import java.util.Map;
044import java.util.Set;
045
046import javax.swing.JComponent;
047import javax.swing.JLabel;
048import javax.swing.JPanel;
049import javax.swing.JSplitPane;
050
051import org.slf4j.Logger;
052import org.slf4j.LoggerFactory;
053
054import ucar.unidata.data.DataCategory;
055import ucar.unidata.data.DataChoice;
056import ucar.unidata.data.DataSelection;
057import ucar.unidata.data.DataSelectionComponent;
058import ucar.unidata.data.DataSourceDescriptor;
059import ucar.unidata.data.DirectDataChoice;
060import ucar.unidata.data.GeoLocationInfo;
061import ucar.unidata.data.GeoSelection;
062import ucar.unidata.util.Misc;
063
064import visad.CommonUnit;
065import visad.CoordinateSystem;
066import visad.Data;
067import visad.FlatField;
068import visad.FunctionType;
069import visad.Gridded2DSet;
070import visad.Linear2DSet;
071import visad.RealTupleType;
072import visad.RealType;
073import visad.SetType;
074import visad.VisADException;
075import visad.georef.MapProjection;
076
077import edu.wisc.ssec.mcidasv.Constants;
078import edu.wisc.ssec.mcidasv.control.LambertAEA;
079import edu.wisc.ssec.mcidasv.data.ComboDataChoice;
080import edu.wisc.ssec.mcidasv.data.HydraDataSource;
081import edu.wisc.ssec.mcidasv.data.PreviewSelection;
082import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
083
084/**
085 * A data source for Multi Dimension Data 
086 */
087
088public class MultiSpectralDataSource extends HydraDataSource {
089
090        private static final Logger logger = LoggerFactory.getLogger(MultiSpectralDataSource.class);
091        
092        /** Sources file */
093    protected String filename;
094
095    protected MultiDimensionReader reader;
096
097    protected MultiDimensionAdapter[] adapters = null;
098
099    private static final String DATA_DESCRIPTION = "Multi Dimension Data";
100
101
102    private Map<String, double[]> defaultSubset;
103    private SwathAdapter swathAdapter;
104    private SpectrumAdapter spectrumAdapter;
105    private MultiSpectralData multiSpectData;
106
107    private List<MultiSpectralData> multiSpectData_s = new ArrayList<>();
108    private Map<String, MultiSpectralData> adapterMap = new HashMap<>();
109
110    private List categories;
111    private boolean hasImagePreview = false;
112    private boolean hasChannelSelect = false;
113
114    private boolean doAggregation = false;
115
116    private ComboDataChoice comboChoice;
117
118    private PreviewSelection previewSelection = null;
119    private FlatField previewImage = null;
120
121    public static final String paramKey = "paramKey";
122
123    /**
124     * Zero-argument constructor for construction via unpersistence.
125     */
126    public MultiSpectralDataSource() {}
127
128    public MultiSpectralDataSource(String fileName) throws VisADException {
129      this(null, Misc.newList(fileName), null);
130    }
131
132    /**
133     * Construct a new HYDRA hdf data source.
134     * @param  descriptor  descriptor for this {@code DataSource}
135     * @param  fileName  name of the hdf file to read
136     * @param  properties  hashtable of properties
137     *
138     * @throws VisADException problem creating data
139     */
140    public MultiSpectralDataSource(DataSourceDescriptor descriptor,
141                                 String fileName, Hashtable properties)
142            throws VisADException {
143        this(descriptor, Misc.newList(fileName), properties);
144    }
145
146    /**
147     * Construct a new HYDRA hdf data source.
148     * @param  descriptor  descriptor for this {@code DataSource}
149     * @param  newSources   List of filenames
150     * @param  properties  hashtable of properties
151     *
152     * @throws VisADException problem creating data
153     */
154    public MultiSpectralDataSource(DataSourceDescriptor descriptor,
155                                 List newSources, Hashtable properties)
156            throws VisADException {
157        super(descriptor, newSources, DATA_DESCRIPTION, properties);
158
159        this.filename = (String)sources.get(0);
160
161        try {
162          setup();
163        }
164        catch (Exception e) {
165          throw new VisADException("could not set up data source", e);
166        }
167    }
168
169    public void setup() throws Exception {
170        String name = (new File(filename)).getName();
171        // aggregations will use sets of NetCDFFile readers
172        List<NetCDFFile> ncdfal = new ArrayList<>();
173
174        try {
175          if (name.startsWith("NSS.HRPT.NP") && name.endsWith("obs.hdf")) { // get file union
176            String other = filename.replace("obs", "nav");
177            reader = NetCDFFile.makeUnion(filename, other);
178          }
179          /**
180          else if (name.startsWith("MYD021KM")) { //hack test code
181            //reader = new NetCDFFileUnion(new String[] {filename, "/Users/rink/Downloads/MYD03.A2011331.0405.005.2011332200700.hdf"}); 
182            reader = new NetCDFFile(filename);
183          }
184          */
185          else {
186                  if (sources.size() > 1) {
187                          for (int i = 0; i < sources.size(); i++) {
188                                  String s = (String) sources.get(i);
189                                  ncdfal.add(new NetCDFFile(s));
190                          }
191                          doAggregation = true;
192                  } else {
193                          reader = new NetCDFFile(filename);
194                  }
195          }
196        }
197        catch (Exception e) {
198                e.printStackTrace();
199                logger.error("Cannot create NetCDF reader for file: " + filename);
200        }
201                                                                                                                                                     
202        Hashtable<String, String[]> properties = new Hashtable<>();
203
204        multiSpectData_s.clear();
205
206        // AIRS data
207        if (name.startsWith("AIRS")) {
208                // make two data choices, Radiance and BrightnessTemperature
209                // index 0: Rad, index 1: BT
210                int choiceCount = 2;
211                for (int i = 0; i < choiceCount; i++) {
212                Map<String, Object> table = SpectrumAdapter.getEmptyMetadataTable();
213                        if (i == 0) {
214                                table.put(SpectrumAdapter.array_name, "L1B_AIRS_Science/Data_Fields/radiances");
215                                table.put(SpectrumAdapter.range_name, "Radiance");
216                        } else {
217                                table.put(SpectrumAdapter.array_name, "L1B_AIRS_Science/Data_Fields/radiances");
218                                table.put(SpectrumAdapter.range_name, "BrightnessTemperature");
219                        }
220
221                        table.put(SpectrumAdapter.channelIndex_name, "Channel");
222                        table.put(SpectrumAdapter.ancillary_file_name, "/edu/wisc/ssec/mcidasv/data/hydra/resources/airs/L2.chan_prop.2003.11.19.v6.6.9.anc");
223                        table.put(SpectrumAdapter.x_dim_name, "GeoXTrack");
224                        table.put(SpectrumAdapter.y_dim_name, "GeoTrack");
225                        SpectrumAdapter spectrumAdapter = new AIRS_L1B_Spectrum(reader, table);
226
227                        table = SwathAdapter.getEmptyMetadataTable();
228                        if (i == 0) {
229                                table.put(SwathAdapter.array_name, "L1B_AIRS_Science/Data_Fields/radiances");
230                                table.put(SwathAdapter.range_name, "Radiance");
231                        } else {
232                                table.put(SwathAdapter.array_name, "L1B_AIRS_Science/Data_Fields/radiances");
233                                table.put(SwathAdapter.range_name, "BrightnessTemperature");
234                        }
235                        table.put("lon_array_name", "L1B_AIRS_Science/Geolocation_Fields/Longitude");
236                        table.put("lat_array_name", "L1B_AIRS_Science/Geolocation_Fields/Latitude");
237                        table.put("XTrack", "GeoXTrack");
238                        table.put("Track", "GeoTrack");
239                        table.put("geo_Track", "GeoTrack");
240                        table.put("geo_XTrack", "GeoXTrack");
241                        table.put(SpectrumAdapter.channelIndex_name, "Channel"); //- think about this?
242
243                        SwathAdapter swathAdapter = new SwathAdapter(reader, table);
244                        Map<String, double[]> subset = swathAdapter.getDefaultSubset();
245                        subset.put(SpectrumAdapter.channelIndex_name, new double[] {793,793,1});
246                        defaultSubset = subset;
247
248                        multiSpectData = new MultiSpectralData(swathAdapter, spectrumAdapter);
249                        // Need to change paramater and range for Radiance, default is Brightness Temp, so
250                        // do nothing for 2nd time through loop
251                        if (i == 0) {
252                                multiSpectData.setParamName("Radiance");
253                                float [] radianceRange = new float[] {-20.0f, 140.0f};
254                                multiSpectData.setDataRange(radianceRange);
255                        }
256                        DataCategory.createCategory("MultiSpectral");
257                        categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;IMAGE");
258                        hasChannelSelect = true;
259                        multiSpectData.init_wavenumber = 919.5f; 
260
261                        multiSpectData_s.add(multiSpectData);
262                }
263        }
264       else if ( name.startsWith("IASI_xxx_1C") && name.endsWith("h5")) {
265          Map<String, Object> table = SpectrumAdapter.getEmptyMetadataTable();
266          table.put(SpectrumAdapter.array_name, "U-MARF/EPS/IASI_xxx_1C/DATA/SPECT_DATA");
267          table.put(SpectrumAdapter.channelIndex_name, "dim2");
268          table.put(SpectrumAdapter.x_dim_name, "dim1");
269          table.put(SpectrumAdapter.y_dim_name, "dim0");
270          spectrumAdapter = new IASI_L1C_Spectrum(reader, table);
271                                                                                                                                             
272          table = SwathAdapter.getEmptyMetadataTable();
273          table.put("array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/SPECT_DATA");
274          table.put("lon_array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/SPECT_LON_ARRAY");
275          table.put("lat_array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/SPECT_LAT_ARRAY");
276          table.put("XTrack", "dim1");
277          table.put("Track", "dim0");
278          table.put("geo_XTrack", "dim1");
279          table.put("geo_Track", "dim0");
280          table.put("product_name", "IASI_L1C_xxx");
281          table.put(SpectrumAdapter.channelIndex_name, "dim2");
282          swathAdapter = new IASI_L1C_SwathAdapter(reader, table);
283          Map<String, double[]> subset = swathAdapter.getDefaultSubset();
284          subset.put(SpectrumAdapter.channelIndex_name, new double[] {793,793,1});
285          defaultSubset = subset;
286          multiSpectData = new MultiSpectralData(swathAdapter, spectrumAdapter);
287          DataCategory.createCategory("MultiSpectral");
288          categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;");
289          multiSpectData.init_wavenumber = 919.5f; 
290          hasChannelSelect = true;
291          multiSpectData_s.add(multiSpectData);
292       }
293       else if ( name.startsWith("IASI")) {
294          Map<String, Object> table = SpectrumAdapter.getEmptyMetadataTable();
295          table.put(SpectrumAdapter.array_name, "observations");
296          table.put(SpectrumAdapter.channelIndex_name, "obsChannelIndex");
297          table.put(SpectrumAdapter.x_dim_name, "obsElement");
298          table.put(SpectrumAdapter.y_dim_name, "obsLine");
299          table.put(SpectrumAdapter.channels_name, "observationChannels");
300          spectrumAdapter = new SpectrumAdapter(reader, table);
301
302          table = SwathAdapter.getEmptyMetadataTable();
303          table.put("array_name", "observations");
304          table.put("lon_array_name", "obsLongitude");
305          table.put("lat_array_name", "obsLatitude");
306          table.put("XTrack", "obsElement");
307          table.put("Track", "obsLine");
308          table.put("geo_XTrack", "obsElement");
309          table.put("geo_Track", "obsLine");
310          table.put(SpectrumAdapter.channelIndex_name, "obsChannelIndex"); //- think about this?
311          swathAdapter = new SwathAdapter(reader, table);
312          Map<String, double[]> subset = swathAdapter.getDefaultSubset();
313          subset.put(SpectrumAdapter.channelIndex_name, new double[] {793,793,1});
314          defaultSubset = subset;
315          multiSpectData = new MultiSpectralData(swathAdapter, spectrumAdapter);
316          DataCategory.createCategory("MultiSpectral");
317          categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;");
318          multiSpectData.init_wavenumber = 919.5f; 
319          multiSpectData_s.add(multiSpectData);
320          hasChannelSelect = true;
321       }
322       else if (name.startsWith("MOD021KM") || name.startsWith("MYD021KM") || 
323               (name.startsWith("a1") && (name.indexOf("1000m") > 0)) || 
324               (name.startsWith("t1") && (name.indexOf("1000m") > 0)) ) {
325         Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
326         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_1KM_Emissive");
327         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
328         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
329         //table.put("lon_array_name", "MODIS_Swath_Type_GEO/Geolocation_Fields/Longitude");
330         //table.put("lat_array_name", "MODIS_Swath_Type_GEO/Geolocation_Fields/Latitude");
331         table.put("XTrack", "Max_EV_frames");
332         table.put("Track", "10*nscans");
333         table.put("geo_Track", "2*nscans");
334         table.put("geo_XTrack", "1KM_geo_dim");
335         //table.put("geo_Track", "nscans*10");
336         //table.put("geo_XTrack", "mframes");
337         table.put("scale_name", "radiance_scales");
338         table.put("offset_name", "radiance_offsets");
339         table.put("fill_value_name", "_FillValue");
340         table.put("range_name", "Emissive_Bands");
341         table.put(SpectrumAdapter.channelIndex_name, "Band_1KM_Emissive");
342         table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
343         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
344         table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
345         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0));
346         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
347         
348         // initialize the aggregation reader object
349         logger.debug("Trying to create MODIS 1K GranuleAggregation reader...");
350         Set<String> products = new LinkedHashSet<>();
351         products.add((String) table.get("array_name"));
352         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_1KM_RefSB");
353         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr1km_RefSB");
354         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_500_Aggr1km_RefSB");
355         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr500_RefSB");
356         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_250_RefSB");
357         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_500_RefSB");
358         products.add((String) table.get("lon_array_name"));
359         products.add((String) table.get("lat_array_name"));
360         if (doAggregation) {
361                 try {
362                         reader = new GranuleAggregation(ncdfal, products, "10*nscans", "2*nscans", "Max_EV_frames");
363                 } catch (Exception e) {
364                         throw new VisADException("Unable to initialize aggregation reader", e);
365                 }
366         }
367
368         swathAdapter = new SwathAdapter(reader, table);
369         swathAdapter.setDefaultStride(10);
370         logger.debug("Trying to create MODIS 1K SwathAdapter...");
371
372         Map<String, double[]> subset = swathAdapter.getDefaultSubset();
373
374         table = SpectrumAdapter.getEmptyMetadataTable();
375         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_1KM_Emissive");
376         table.put(SpectrumAdapter.channelIndex_name, "Band_1KM_Emissive");
377         table.put(SpectrumAdapter.x_dim_name, "Max_EV_frames");
378         table.put(SpectrumAdapter.y_dim_name, "10*nscans");
379         table.put(SpectrumAdapter.channelValues, new float[]
380           {3.799f,3.992f,3.968f,4.070f,4.476f,4.549f,6.784f,7.345f,8.503f,
381            9.700f,11.000f,12.005f,13.351f,13.717f,13.908f,14.205f});
382         table.put(SpectrumAdapter.bandNames, new String[] 
383           {"20","21","22","23","24","25","27","28","29",
384            "30","31","32","33","34","35","36"});
385         table.put(SpectrumAdapter.channelType, "wavelength");
386         SpectrumAdapter spectrumAdapter = new SpectrumAdapter(reader, table);
387
388         multiSpectData = new MultiSpectralData(swathAdapter, spectrumAdapter, "MODIS", "Aqua");
389         multiSpectData.setInitialWavenumber(11.0f);
390         defaultSubset = multiSpectData.getDefaultSubset();
391
392         previewImage = multiSpectData.getImage(defaultSubset);
393         multiSpectData_s.add(multiSpectData);
394
395         //--- aggregate reflective bands
396         table = SwathAdapter.getEmptyMetadataTable();
397
398         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_1KM_RefSB");
399         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
400         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
401         table.put("XTrack", "Max_EV_frames");
402         table.put("Track", "10*nscans");
403         table.put("geo_Track", "2*nscans");
404         table.put("geo_XTrack", "1KM_geo_dim");
405         table.put("scale_name", "reflectance_scales");
406         table.put("offset_name", "reflectance_offsets");
407         table.put("fill_value_name", "_FillValue");
408         table.put("range_name", "EV_1KM_RefSB");
409         table.put(SpectrumAdapter.channelIndex_name, "Band_1KM_RefSB");
410
411         table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
412         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
413         table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
414         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0));
415         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
416
417         SwathAdapter sadapt0 = new SwathAdapter(reader, table);
418         sadapt0.setDefaultStride(10);
419
420         table = SpectrumAdapter.getEmptyMetadataTable();
421         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_1KM_RefSB");
422         table.put(SpectrumAdapter.channelIndex_name, "Band_1KM_RefSB");
423         table.put(SpectrumAdapter.x_dim_name, "Max_EV_frames");
424         table.put(SpectrumAdapter.y_dim_name, "10*nscans");
425         table.put(SpectrumAdapter.channelValues, new float[]
426            {.412f,.450f,.487f,.531f,.551f,.666f,.668f,.677f,.679f,.748f,
427             .869f,.905f,.936f,.940f,1.375f});
428         table.put(SpectrumAdapter.bandNames, new String[]
429            {"8","9","10","11","12","13lo","13hi","14lo","14hi","15",
430             "16","17","18","19","26"});
431         table.put(SpectrumAdapter.channelType, "wavelength");
432         SpectrumAdapter specadap0 = new SpectrumAdapter(reader, table);
433         MultiSpectralData multispec0 = new MultiSpectralData(sadapt0, specadap0, "Reflectance", "Reflectance", "MODIS", "Aqua");
434
435         DataCategory.createCategory("MultiSpectral");
436         categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;IMAGE");
437         hasImagePreview = true;
438         hasChannelSelect = true;
439
440         table = SwathAdapter.getEmptyMetadataTable();
441
442         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr1km_RefSB");
443         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
444         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
445         table.put("XTrack", "Max_EV_frames");
446         table.put("Track", "10*nscans");
447         table.put("geo_Track", "2*nscans");
448         table.put("geo_XTrack", "1KM_geo_dim");
449         table.put("scale_name", "reflectance_scales");
450         table.put("offset_name", "reflectance_offsets");
451         table.put("fill_value_name", "_FillValue");
452         table.put("range_name", "Reflective_Bands");
453         table.put(SpectrumAdapter.channelIndex_name, "Band_250M");
454
455         table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
456         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
457         table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
458         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0));
459         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
460
461         SwathAdapter sadapt1 = new SwathAdapter(reader, table);
462
463         table = SpectrumAdapter.getEmptyMetadataTable();
464         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr1km_RefSB");
465         table.put(SpectrumAdapter.channelIndex_name, "Band_250M");
466         table.put(SpectrumAdapter.x_dim_name, "Max_EV_frames");
467         table.put(SpectrumAdapter.y_dim_name, "10*nscans");
468         table.put(SpectrumAdapter.channelValues, new float[]
469            {.650f,.855f});
470         table.put(SpectrumAdapter.bandNames, new String[]
471            {"1","2"});
472         table.put(SpectrumAdapter.channelType, "wavelength");
473         SpectrumAdapter specadap1 = new SpectrumAdapter(reader, table);
474         MultiSpectralData multispec1 = new MultiSpectralData(sadapt1, specadap1, "Reflectance", "Reflectance", "MODIS", "Aqua");
475
476         table = SwathAdapter.getEmptyMetadataTable();
477
478         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_500_Aggr1km_RefSB");
479         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
480         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
481         table.put("XTrack", "Max_EV_frames");
482         table.put("Track", "10*nscans");
483         table.put("geo_Track", "2*nscans");
484         table.put("geo_XTrack", "1KM_geo_dim");
485         table.put("scale_name", "reflectance_scales");
486         table.put("offset_name", "reflectance_offsets");
487         table.put("fill_value_name", "_FillValue");
488         table.put("range_name", "EV_500_Aggr1km_RefSB");
489         table.put(SpectrumAdapter.channelIndex_name, "Band_500M");
490         table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
491         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
492         table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
493         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0));
494         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
495
496
497         SwathAdapter sadapt2 = new SwathAdapter(reader, table);
498
499
500         table = SpectrumAdapter.getEmptyMetadataTable();
501         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_500_Aggr1km_RefSB");
502         table.put(SpectrumAdapter.channelIndex_name, "Band_500M");
503         table.put(SpectrumAdapter.x_dim_name, "Max_EV_frames");
504         table.put(SpectrumAdapter.y_dim_name, "10*nscans");
505         table.put(SpectrumAdapter.channelValues, new float[]
506            {.470f,.555f,1.240f,1.638f,2.130f});
507         table.put(SpectrumAdapter.bandNames, new String[]
508            {"3","4","5","6","7"});
509         table.put(SpectrumAdapter.channelType, "wavelength");
510         SpectrumAdapter specadap2 = new SpectrumAdapter(reader, table);
511         MultiSpectralData multispec2 = new MultiSpectralData(sadapt2, specadap2, "Reflectance", "Reflectance", "MODIS", "Aqua");
512
513         MultiSpectralAggr aggr = new MultiSpectralAggr(new MultiSpectralData[] {multispec1, multispec2, multispec0});
514         aggr.setInitialWavenumber(0.650f);
515         aggr.setDataRange(new float[] {0f, 0.8f});
516         multiSpectData_s.add(aggr);
517       }
518       else if (name.startsWith("MOD02QKM") || name.startsWith("MYD02QKM") ||
519               (name.startsWith("a1") && (name.indexOf("250m") > 0)) ||
520               (name.startsWith("t1") && (name.indexOf("250m") > 0)) ) {
521         Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
522         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_250_RefSB");
523         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
524         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
525         table.put("XTrack", "4*Max_EV_frames");
526         table.put("Track", "40*nscans");
527         table.put("geo_Track", "10*nscans");
528         table.put("geo_XTrack", "Max_EV_frames");
529         table.put("scale_name", "reflectance_scales");
530         table.put("offset_name", "reflectance_offsets");
531         table.put("fill_value_name", "_FillValue");
532         table.put("range_name", "Reflective_Bands");
533         table.put(SpectrumAdapter.channelIndex_name, "Band_250M");
534         table.put(SwathAdapter.geo_track_offset_name, Double.toString(0.0));
535         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(0.0));
536         table.put(SwathAdapter.geo_track_skip_name, Double.toString(4.0));
537         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(4.0));
538         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
539         // initialize the aggregation reader object
540         logger.debug("Trying to create MODIS 1K GranuleAggregation reader...");
541         LinkedHashSet<String> products = new LinkedHashSet<String>();
542         products.add((String) table.get("array_name"));
543         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_250_RefSB");
544         products.add((String) table.get("lon_array_name"));
545         products.add((String) table.get("lat_array_name"));
546         if (doAggregation) {
547                 try {
548                         reader = new GranuleAggregation(ncdfal, products, "40*nscans", "10*nscans", "4*Max_EV_frames");
549                 } catch (Exception e) {
550                         throw new VisADException("Unable to initialize aggregation reader", e);
551                 }
552         }
553         swathAdapter = new SwathAdapter(reader, table);
554         swathAdapter.setDefaultStride(40);
555
556         table = SpectrumAdapter.getEmptyMetadataTable();
557         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_250_RefSB");
558         table.put(SpectrumAdapter.channelIndex_name, "Band_250M");
559         table.put(SpectrumAdapter.x_dim_name, "4*Max_EV_frames");
560         table.put(SpectrumAdapter.y_dim_name, "40*nscans");
561         table.put(SpectrumAdapter.channelValues, new float[]
562            {.650f,.855f});
563         table.put(SpectrumAdapter.bandNames, new String[]
564            {"1","2"});
565         table.put(SpectrumAdapter.channelType, "wavelength");
566         SpectrumAdapter spectrumAdapter = new SpectrumAdapter(reader, table);
567
568         multiSpectData = new MultiSpectralData(swathAdapter, spectrumAdapter, "Reflectance", "Reflectance", "MODIS", "Aqua");
569         multiSpectData.setInitialWavenumber(0.650f);
570         multiSpectData.setDataRange(new float[] {0f, 0.8f});
571         defaultSubset = multiSpectData.getDefaultSubset();
572         previewImage = multiSpectData.getImage(defaultSubset);
573         multiSpectData_s.add(multiSpectData);
574
575         DataCategory.createCategory("MultiSpectral");
576         categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;IMAGE");
577         hasImagePreview = true;
578         hasChannelSelect = true;
579
580         multiSpectData_s.add(null);
581       }
582       else if (name.startsWith("MOD02HKM") || name.startsWith("MYD02HKM") ||
583               (name.startsWith("a1") && (name.indexOf("500m") > 0)) ||
584               (name.startsWith("t1") && (name.indexOf("500m") > 0)) ) {
585         Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
586         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr500_RefSB");
587         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
588         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
589         table.put("XTrack", "2*Max_EV_frames");
590         table.put("Track", "20*nscans");
591         table.put("geo_Track", "10*nscans");
592         table.put("geo_XTrack", "Max_EV_frames");
593         table.put("scale_name", "reflectance_scales");
594         table.put("offset_name", "reflectance_offsets");
595         table.put("fill_value_name", "_FillValue");
596         table.put("range_name", "Reflective_Bands");
597         table.put(SpectrumAdapter.channelIndex_name, "Band_250M");
598         table.put(SwathAdapter.geo_track_offset_name, Double.toString(0.0));
599         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(0.0));
600         table.put(SwathAdapter.geo_track_skip_name, Double.toString(2.0));
601         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(2.0));
602         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
603
604         // initialize the aggregation reader object
605         logger.debug("Trying to create MODIS 1K GranuleAggregation reader...");
606         LinkedHashSet<String> products = new LinkedHashSet<String>();
607         products.add((String) table.get("array_name"));
608         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_500_RefSB");
609         products.add("MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr500_RefSB");
610         products.add((String) table.get("lon_array_name"));
611         products.add((String) table.get("lat_array_name"));
612         if (doAggregation) {
613                 try {
614                         reader = new GranuleAggregation(ncdfal, products, "20*nscans", "10*nscans", "2*Max_EV_frames");
615                 } catch (Exception e) {
616                         throw new VisADException("Unable to initialize aggregation reader", e);
617                 }
618         }
619
620         SwathAdapter swathAdapter0 = new SwathAdapter(reader, table);
621         swathAdapter0.setDefaultStride(20);
622
623         table = SpectrumAdapter.getEmptyMetadataTable();
624         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_250_Aggr500_RefSB");
625         table.put(SpectrumAdapter.channelIndex_name, "Band_250M");
626         table.put(SpectrumAdapter.x_dim_name, "2*Max_EV_frames");
627         table.put(SpectrumAdapter.y_dim_name, "20*nscans");
628         table.put(SpectrumAdapter.channelValues, new float[]
629            {.650f,.855f});
630         table.put(SpectrumAdapter.bandNames, new String[]
631            {"1","2"});
632         table.put(SpectrumAdapter.channelType, "wavelength");
633         SpectrumAdapter spectrumAdapter0 = new SpectrumAdapter(reader, table);
634
635         MultiSpectralData multiSpectData0 = new MultiSpectralData(swathAdapter0, spectrumAdapter0, "Reflectance", "Reflectance", "MODIS", "Aqua");
636
637         table = SwathAdapter.getEmptyMetadataTable();
638         table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_500_RefSB");
639         table.put("lon_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Longitude");
640         table.put("lat_array_name", "MODIS_SWATH_Type_L1B/Geolocation_Fields/Latitude");
641         table.put("XTrack", "2*Max_EV_frames");
642         table.put("Track", "20*nscans");
643         table.put("geo_Track", "10*nscans");
644         table.put("geo_XTrack", "Max_EV_frames");
645         table.put("scale_name", "reflectance_scales");
646         table.put("offset_name", "reflectance_offsets");
647         table.put("fill_value_name", "_FillValue");
648         table.put("range_name", "Reflective_Bands");
649         table.put(SpectrumAdapter.channelIndex_name, "Band_500M");
650         table.put(SwathAdapter.geo_track_offset_name, Double.toString(0.0));
651         table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(0.0));
652         table.put(SwathAdapter.geo_track_skip_name, Double.toString(2.0));
653         table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(2.0));
654         table.put(SwathAdapter.multiScaleDimensionIndex, Integer.toString(0));
655
656         SwathAdapter swathAdapter1 = new SwathAdapter(reader, table);
657         swathAdapter1.setDefaultStride(20);
658
659         table = SpectrumAdapter.getEmptyMetadataTable();
660         table.put(SpectrumAdapter.array_name, "MODIS_SWATH_Type_L1B/Data_Fields/EV_500_RefSB");
661         table.put(SpectrumAdapter.channelIndex_name, "Band_500M");
662         table.put(SpectrumAdapter.x_dim_name, "2*Max_EV_frames");
663         table.put(SpectrumAdapter.y_dim_name, "20*nscans");
664         table.put(SpectrumAdapter.channelValues, new float[]
665            {.470f,.555f,1.240f,1.638f,2.130f});
666         table.put(SpectrumAdapter.bandNames, new String[]
667            {"3","4","5","6","7"});
668         table.put(SpectrumAdapter.channelType, "wavelength");
669         SpectrumAdapter spectrumAdapter1 = new SpectrumAdapter(reader, table);
670
671         MultiSpectralData multiSpectData1 = new MultiSpectralData(swathAdapter1, spectrumAdapter1, "Reflectance", "Reflectance", "MODIS", "Aqua");
672
673         MultiSpectralAggr aggr = 
674            new MultiSpectralAggr(new MultiSpectralData[] {multiSpectData0, multiSpectData1});
675         aggr.setInitialWavenumber(0.650f);
676         aggr.setDataRange(new float[] {0f, 0.8f});
677         multiSpectData_s.add(aggr);
678         multiSpectData = aggr;
679         defaultSubset = aggr.getDefaultSubset();
680         previewImage = aggr.getImage(defaultSubset);
681
682         DataCategory.createCategory("MultiSpectral");
683         categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;IMAGE");
684         hasImagePreview = true;
685         hasChannelSelect = true;
686
687         multiSpectData_s.add(null);
688       }
689       else if (name.startsWith("NSS.HRPT") && name.endsWith("level2.hdf")) {
690         Map<String, Object> swthTable = SwathAdapter.getEmptyMetadataTable();
691         swthTable.put("array_name", "temp_3_75um_nom");
692         swthTable.put("lon_array_name", "longitude");
693         swthTable.put("lat_array_name", "latitude");
694         swthTable.put("XTrack", "pixel_elements_along_scan_direction");
695         swthTable.put("Track", "scan_lines_along_track_direction");
696         swthTable.put("geo_Track", "scan_lines_along_track_direction");
697         swthTable.put("geo_XTrack", "pixel_elements_along_scan_direction");
698         swthTable.put("scale_name", "SCALE_FACTOR");
699         swthTable.put("offset_name", "ADD_OFFSET");
700         swthTable.put("fill_value_name", "_FILLVALUE");
701         swthTable.put("range_name", "Emmissive_Bands");
702         swthTable.put("unpack", "unpack");
703         swthTable.put("geo_scale_name", "SCALE_FACTOR");
704         swthTable.put("geo_offset_name", "ADD_OFFSET");
705         swthTable.put("geo_fillValue_name", "_FILLVALUE");
706
707
708         SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
709         swathAdapter0.setDefaultStride(10);
710         Map<String, double[]> subset = swathAdapter0.getDefaultSubset();
711         defaultSubset = subset;
712
713         Map<String, Object> specTable = SpectrumAdapter.getEmptyMetadataTable();
714         specTable.put(SpectrumAdapter.array_name, "temp_3_75um_nom");
715         specTable.put(SpectrumAdapter.x_dim_name, "pixel_elements_along_scan_direction");
716         specTable.put(SpectrumAdapter.y_dim_name, "scan_lines_along_track_direction");
717         specTable.put(SpectrumAdapter.channelValues, new float[] {3.740f});
718         specTable.put(SpectrumAdapter.bandNames, new String[] {"ch3b"});
719         specTable.put(SpectrumAdapter.channelType, "wavelength");
720         SpectrumAdapter spectrumAdapter0 = new SpectrumAdapter(reader, specTable);
721
722         MultiSpectralData multiSpectData0 = new MultiSpectralData(swathAdapter0, spectrumAdapter0, "BrightnessTemp", "BrightnessTemp", null, null);
723
724         Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
725         table.put("array_name", "temp_11_0um_nom");
726         table.put("lon_array_name", "longitude");
727         table.put("lat_array_name", "latitude");
728         table.put("XTrack", "pixel_elements_along_scan_direction");
729         table.put("Track", "scan_lines_along_track_direction");
730         table.put("geo_Track", "scan_lines_along_track_direction");
731         table.put("geo_XTrack", "pixel_elements_along_scan_direction");
732         table.put("scale_name", "SCALE_FACTOR");
733         table.put("offset_name", "ADD_OFFSET");
734         table.put("fill_value_name", "_FILLVALUE");
735         table.put("range_name", "Emmissive_Bands");
736         table.put("unpack", "unpack");
737         table.put("geo_scale_name", "SCALE_FACTOR");
738         table.put("geo_offset_name", "ADD_OFFSET");
739         table.put("geo_fillValue_name", "_FILLVALUE");
740
741
742         SwathAdapter swathAdapter1 = new SwathAdapter(reader, table);
743         swathAdapter1.setDefaultStride(10);
744
745         table = SpectrumAdapter.getEmptyMetadataTable();
746         table.put(SpectrumAdapter.array_name, "temp_11_0um_nom");
747         table.put(SpectrumAdapter.x_dim_name, "pixel_elements_along_scan_direction");
748         table.put(SpectrumAdapter.y_dim_name, "scan_lines_along_track_direction");
749         table.put(SpectrumAdapter.channelValues, new float[] {10.80f});
750         table.put(SpectrumAdapter.bandNames, new String[] {"ch4"});
751         table.put(SpectrumAdapter.channelType, "wavelength");
752         SpectrumAdapter spectrumAdapter1 = new SpectrumAdapter(reader, table);
753
754         MultiSpectralData multiSpectData1 = new MultiSpectralData(swathAdapter1, spectrumAdapter1, "BrightnessTemp", "BrightnessTemp", null, null);
755
756         table = SwathAdapter.getEmptyMetadataTable();
757         table.put("array_name", "temp_12_0um_nom");
758         table.put("lon_array_name", "longitude");
759         table.put("lat_array_name", "latitude");
760         table.put("XTrack", "pixel_elements_along_scan_direction");
761         table.put("Track", "scan_lines_along_track_direction");
762         table.put("geo_Track", "scan_lines_along_track_direction");
763         table.put("geo_XTrack", "pixel_elements_along_scan_direction");
764         table.put("scale_name", "SCALE_FACTOR");
765         table.put("offset_name", "ADD_OFFSET");
766         table.put("fill_value_name", "_FILLVALUE");
767         table.put("range_name", "Emmissive_Bands");
768         table.put("unpack", "unpack");
769         table.put("geo_scale_name", "SCALE_FACTOR");
770         table.put("geo_offset_name", "ADD_OFFSET");
771         table.put("geo_fillValue_name", "_FILLVALUE");
772
773
774         SwathAdapter swathAdapter2 = new SwathAdapter(reader, table);
775         swathAdapter2.setDefaultStride(10);
776
777         table = SpectrumAdapter.getEmptyMetadataTable();
778         table.put(SpectrumAdapter.array_name, "temp_12_0um_nom");
779         table.put(SpectrumAdapter.x_dim_name, "pixel_elements_along_scan_direction");
780         table.put(SpectrumAdapter.y_dim_name, "scan_lines_along_track_direction");
781         table.put(SpectrumAdapter.channelValues, new float[] {12.00f});
782         table.put(SpectrumAdapter.bandNames, new String[] {"ch5"});
783         table.put(SpectrumAdapter.channelType, "wavelength");
784         SpectrumAdapter spectrumAdapter2 = new SpectrumAdapter(reader, table);
785
786         MultiSpectralData multiSpectData2 = new MultiSpectralData(swathAdapter2, spectrumAdapter2, "BrightnessTemp", "BrightnessTemp", null, null);
787
788
789         MultiSpectralAggr aggr = new MultiSpectralAggr(new MultiSpectralData[] {multiSpectData0, multiSpectData1, multiSpectData2});
790         aggr.setInitialWavenumber(3.740f);
791         aggr.setDataRange(new float[] {180f, 340f});
792         multiSpectData = aggr;
793         multiSpectData_s.add(aggr);
794         defaultSubset = aggr.getDefaultSubset();
795         previewImage = aggr.getImage(defaultSubset);
796
797         //- now do the reflective bands
798         swthTable.put("array_name", "refl_0_65um_nom");
799         swthTable.put("range_name", "Reflective_Bands");
800
801         swathAdapter0 = new SwathAdapter(reader, swthTable);
802         swathAdapter0.setDefaultStride(10);
803
804         specTable.put(SpectrumAdapter.array_name, "refl_0_65um_nom");
805         specTable.put(SpectrumAdapter.channelValues, new float[] {0.630f});
806         specTable.put(SpectrumAdapter.bandNames, new String[] {"ch1"});
807         spectrumAdapter0 = new SpectrumAdapter(reader, specTable);
808
809         multiSpectData0 = new MultiSpectralData(swathAdapter0, spectrumAdapter0, "Reflectance", "Reflectance", null, null);
810
811         swthTable.put("array_name", "refl_0_86um_nom");
812         swthTable.put("range_name", "Reflective_Bands");
813         
814         swathAdapter1 = new SwathAdapter(reader, swthTable);
815         swathAdapter1.setDefaultStride(10);
816         
817         specTable.put(SpectrumAdapter.array_name, "refl_0_86um_nom");
818         specTable.put(SpectrumAdapter.channelValues, new float[] {0.862f});
819         specTable.put(SpectrumAdapter.bandNames, new String[] {"ch2"});
820         spectrumAdapter1 = new SpectrumAdapter(reader, specTable);
821
822         multiSpectData1 = new MultiSpectralData(swathAdapter1, spectrumAdapter1, "Reflectance", "Reflectance", null, null);
823
824         swthTable.put("array_name", "refl_1_60um_nom");
825         swthTable.put("range_name", "Reflective_Bands");
826         
827         swathAdapter2 = new SwathAdapter(reader, swthTable);
828         swathAdapter2.setDefaultStride(10);
829         subset = swathAdapter2.getDefaultSubset();
830         defaultSubset = subset;
831         
832         specTable.put(SpectrumAdapter.array_name, "refl_1_60um_nom");
833         specTable.put(SpectrumAdapter.channelValues, new float[] {1.610f});
834         specTable.put(SpectrumAdapter.bandNames, new String[] {"ch3ab"});
835         spectrumAdapter2 = new SpectrumAdapter(reader, specTable);
836
837         multiSpectData2 = new MultiSpectralData(swathAdapter2, spectrumAdapter2, "Reflectance", "Reflectance", null, null);
838
839         aggr = new MultiSpectralAggr(new MultiSpectralData[] {multiSpectData0, multiSpectData1, multiSpectData2});
840         aggr.setInitialWavenumber(0.630f);
841         aggr.setDataRange(new float[] {0f, 100f});
842         multiSpectData_s.add(aggr);
843
844         categories = DataCategory.parseCategories("MultiSpectral;MultiSpectral;IMAGE");
845
846         hasImagePreview = true;
847         hasChannelSelect = true;
848       }
849       else {
850          Map<String, Object> table = SwathAdapter.getEmptyMetadataTable();
851          table.put("array_name", "MODIS_SWATH_Type_L1B/Data_Fields/EV_1KM_Emissive");
852          table.put("lon_array_name", "pixel_longitude");
853          table.put("lat_array_name", "pixel_latitude");
854          table.put("XTrack", "elements");
855          table.put("Track", "lines");
856          table.put("geo_Track", "lines");
857          table.put("geo_XTrack", "elements");
858          table.put("scale_name", "scale_factor");
859          table.put("offset_name", "add_offset");
860          table.put("fill_value_name", "_FillValue");
861          swathAdapter = new SwathAdapter(reader, table);
862          categories = DataCategory.parseCategories("2D grid;GRID-2D;");
863          defaultSubset = swathAdapter.getDefaultSubset();
864       }
865       setProperties(properties);
866    }
867
868    public void initAfterUnpersistence() {
869      try {
870        setup();
871      } 
872      catch (Exception e) {
873      }
874    }
875
876    /**
877     * Make and insert the {@link DataChoice DataChoices} for this {@code DataSource}.
878     */
879    public void doMakeDataChoices() {
880        try {
881          for (int k=0; k<multiSpectData_s.size(); k++) {
882            MultiSpectralData adapter = multiSpectData_s.get(k);
883            DataChoice choice = doMakeDataChoice(k, adapter);
884            adapterMap.put(choice.getName(), adapter);
885            addDataChoice(choice);
886          }
887        }
888        catch(Exception e) {
889          e.printStackTrace();
890        }
891    }
892
893    public void addChoice(String name, Data data) {
894        ComboDataChoice combo = new ComboDataChoice(name + hashCode(), name, new Hashtable(), data);
895        addDataChoice(combo);
896        getDataContext().dataSourceChanged(this);
897    }
898
899    private DataChoice doMakeDataChoice(int idx, MultiSpectralData adapter) throws Exception {
900        String name = "_    ";
901        DataSelection dataSel = new MultiDimensionSubset();
902        if (adapter != null) {
903          name = adapter.getName();
904          //dataSel = new MultiDimensionSubset(defaultSubset);
905          dataSel = new MultiDimensionSubset(adapter.getDefaultSubset());
906        }
907
908        Hashtable subset = new Hashtable();
909        subset.put(MultiDimensionSubset.key, dataSel);
910        if (adapter != null) {
911          subset.put(MultiSpectralDataSource.paramKey, adapter.getParameter());
912        }
913
914        DirectDataChoice ddc = new DirectDataChoice(this, new Integer(idx), name, name, categories, subset);
915        ddc.setProperties(subset);
916        return ddc;
917    }
918
919    /**
920     * Check to see if this {@code HDFHydraDataSource} is equal to the object
921     * in question.
922     * @param o  object in question
923     * @return true if they are the same or equivalent objects
924     */
925    public boolean equals(Object o) {
926        if ( !(o instanceof MultiSpectralDataSource)) {
927            return false;
928        }
929        return (this == (MultiSpectralDataSource) o);
930    }
931
932    public MultiSpectralData getMultiSpectralData() {
933      return multiSpectData;
934    }
935
936    public MultiSpectralData getMultiSpectralData(DataChoice choice) {
937      return adapterMap.get(choice.getName());
938    }
939
940    public MultiSpectralData getMultiSpectralData(String name) {
941      return adapterMap.get(name);
942    }
943
944    public MultiSpectralData getMultiSpectralData(int idx) {
945      return multiSpectData_s.get(idx);
946    }
947
948    public String getDatasetName() {
949      return filename;
950    }
951
952    public void setDatasetName(String name) {
953      filename = name;
954    }
955
956    public ComboDataChoice getComboDataChoice() {
957      return comboChoice;
958    }
959
960    /**
961     * Called by the IDV's persistence manager in an effort to collect all of
962     * the files that should be included in a zipped bundle.
963     * 
964     * @return Singleton list containing the file that this data source came from.
965     */
966    @Override public List getDataPaths() {
967        return Collections.singletonList(filename);
968    }
969
970  /**
971    public HashMap getSubsetFromLonLatRect(MultiDimensionSubset select, GeoSelection geoSelection) {
972      GeoLocationInfo ginfo = geoSelection.getBoundingBox();
973      return adapters[0].getSubsetFromLonLatRect(select.getSubset(), ginfo.getMinLat(), ginfo.getMaxLat(),
974                                        ginfo.getMinLon(), ginfo.getMaxLon());
975    }
976   */
977
978    public synchronized Data getData(String name, Map<String, double[]> subset) throws VisADException, RemoteException {
979      MultiSpectralData msd =  getMultiSpectralData(name);
980      Data data = null;
981      try {
982        data = msd.getImage(subset);
983      } catch (Exception e) {
984        e.printStackTrace();
985      }
986      return data;
987    }
988
989
990    public synchronized Data getData(DataChoice dataChoice, DataCategory category,
991                                DataSelection dataSelection, Hashtable requestProperties)
992                                throws VisADException, RemoteException {
993       return this.getDataInner(dataChoice, category, dataSelection, requestProperties);
994
995    }
996
997    protected Data getDataInner(DataChoice dataChoice, DataCategory category,
998                                DataSelection dataSelection, Hashtable requestProperties)
999                                throws VisADException, RemoteException {
1000
1001        //- this hack keeps the HydraImageProbe from doing a getData()
1002        //- TODO: need to use categories?
1003        if (requestProperties != null) {
1004          if ((requestProperties.toString()).contains("ReadoutProbe")) {
1005            return null;
1006          }
1007        }
1008
1009        GeoLocationInfo ginfo = null;
1010        GeoSelection geoSelection = null;
1011        
1012        if ((dataSelection != null) && (dataSelection.getGeoSelection() != null)) {
1013          if (dataSelection.getGeoSelection().getBoundingBox() != null) {
1014            geoSelection = dataSelection.getGeoSelection();
1015          }
1016          else if (dataChoice.getDataSelection() != null) {
1017            geoSelection = dataChoice.getDataSelection().getGeoSelection();
1018          }
1019        }
1020
1021        if (geoSelection != null) {
1022          ginfo = geoSelection.getBoundingBox();
1023        }
1024
1025        Data data = null;
1026
1027        try {
1028            Map<String, double[]> subset = null;
1029            if (ginfo != null) {
1030              subset = swathAdapter.getSubsetFromLonLatRect(ginfo.getMinLat(), ginfo.getMaxLat(),
1031                                        ginfo.getMinLon(), ginfo.getMaxLon());
1032            }
1033            else {
1034              MultiDimensionSubset select = null;
1035              Hashtable table = dataChoice.getProperties();
1036              Enumeration keys = table.keys();
1037              while (keys.hasMoreElements()) {
1038                Object key = keys.nextElement();
1039                if (key instanceof MultiDimensionSubset) {
1040                  select = (MultiDimensionSubset) table.get(key);
1041                }
1042              }  
1043              if (select != null) {
1044                subset = select.getSubset();
1045              }
1046
1047              if (dataSelection != null) {
1048                  Hashtable props = dataSelection.getProperties();
1049                  if (props != null) {
1050                    if (props.containsKey(MultiDimensionSubset.key)) {
1051                      subset = (HashMap)((MultiDimensionSubset)props.get(MultiDimensionSubset.key)).getSubset();
1052                    }
1053                    else {
1054                      subset = defaultSubset;
1055                    }
1056                    if (props.containsKey(SpectrumAdapter.channelIndex_name)) {
1057                      int idx = ((Integer) props.get(SpectrumAdapter.channelIndex_name)).intValue();
1058                      double[] coords = subset.get(SpectrumAdapter.channelIndex_name);
1059                      if (coords == null) {
1060                        coords = new double[] {(double)idx, (double)idx, (double)1};
1061                        subset.put(SpectrumAdapter.channelIndex_name, coords);
1062                      }
1063                      else {
1064                        coords[0] = (double)idx;
1065                        coords[1] = (double)idx;
1066                        coords[2] = (double)1;
1067                      }
1068                   }
1069                 }
1070               }
1071            }
1072
1073            if (subset != null) {
1074              MultiSpectralData multiSpectData = getMultiSpectralData(dataChoice);
1075              if (multiSpectData != null) {
1076                data = multiSpectData.getImage(subset);
1077                data = applyProperties(data, requestProperties, subset);
1078              }
1079            }
1080        } catch (Exception e) {
1081            e.printStackTrace();
1082            System.out.println("getData exception e=" + e);
1083        }
1084        return data;
1085    }
1086
1087    public MapProjection getDataProjection(Map<String, double[]> subset) {
1088      MapProjection mp = null;
1089      try {
1090        Rectangle2D rect =  multiSpectData.getLonLatBoundingBox(subset);
1091        mp = new LambertAEA(rect);
1092      }
1093      catch (Exception e) {
1094        logException("MultiSpectralDataSource.getDataProjection", e);
1095      }
1096      return mp;
1097    }
1098
1099    protected Data applyProperties(Data data, Hashtable requestProperties, Map<String, double[]> subset)
1100          throws VisADException, RemoteException {
1101      Data new_data = data;
1102
1103      if (requestProperties == null) {
1104        new_data = data;
1105        return new_data;
1106      }
1107      return new_data;
1108    }
1109
1110    protected void initDataSelectionComponents(
1111         List<DataSelectionComponent> components,
1112             final DataChoice dataChoice) {
1113
1114        // TJJ Nov 2014 - Why did we need an OS-specific check here? Seems this should be the choice 
1115        // each time and in fact Linux no longer works if we drop through, so commenting out [1805]
1116      // if (System.getProperty("os.name").equals("Mac OS X") && hasImagePreview && hasChannelSelect) {
1117      if (hasImagePreview && hasChannelSelect) {
1118        try {
1119          components.add(new ImageChannelSelection(new PreviewSelection(dataChoice, previewImage, null), new ChannelSelection(dataChoice)));
1120        } catch (Exception e) {
1121          e.printStackTrace();
1122        }
1123      }
1124      else {
1125        if (hasImagePreview) {
1126          try {
1127            previewSelection = new PreviewSelection(dataChoice, previewImage, null);
1128            components.add(previewSelection);
1129          } catch (Exception e) {
1130            System.out.println("Can't make PreviewSelection: "+e);
1131            e.printStackTrace();
1132          }
1133        }
1134        if (hasChannelSelect) {
1135          try {
1136            components.add(new ChannelSelection(dataChoice));
1137          } 
1138          catch (Exception e) {
1139            e.printStackTrace();
1140          }
1141        }
1142      }
1143    }
1144
1145
1146  public static MapProjection getDataProjection(FlatField fltField) throws Exception {
1147    Rectangle2D rect = MultiSpectralData.getLonLatBoundingBox(fltField);
1148    MapProjection mp = new LambertAEA(rect, false);
1149    return mp;
1150  }
1151
1152   public static MapProjection getSwathProjection(FlatField image, float[][] corners) throws VisADException, RemoteException {
1153      MapProjection mp = null;
1154      FunctionType fnc_type = (FunctionType) image.getType();
1155      RealTupleType rtt = fnc_type.getDomain();
1156      CoordinateSystem cs = rtt.getCoordinateSystem();
1157      Gridded2DSet domainSet = (Gridded2DSet) image.getDomainSet();
1158
1159      if (cs instanceof visad.CachingCoordinateSystem) {
1160         cs = ((visad.CachingCoordinateSystem)cs).getCachedCoordinateSystem();
1161      }
1162
1163      if (cs instanceof LongitudeLatitudeCoordinateSystem) {
1164         try {
1165           mp = new LambertAEA(corners);
1166         } catch (Exception e) {
1167           System.out.println(" getDataProjection"+e);
1168         }
1169         return mp;
1170      }
1171      else {
1172         return null;
1173      }
1174   }
1175
1176
1177  public static Linear2DSet makeGrid(MapProjection mp, double res) throws Exception {
1178    Rectangle2D rect = mp.getDefaultMapArea();
1179
1180    int xLen = (int) (rect.getWidth()/res);
1181    int yLen = (int) (rect.getHeight()/res);
1182
1183    RealType xmap = RealType.getRealType("xmap", CommonUnit.meter);
1184    RealType ymap = RealType.getRealType("ymap", CommonUnit.meter);
1185
1186    RealTupleType rtt = new visad.RealTupleType(xmap, ymap, mp, null);
1187
1188    Linear2DSet grid = new Linear2DSet(rtt, rect.getX(), (xLen-1)*res, xLen,
1189                                            rect.getY(), (yLen-1)*res, yLen);
1190    return grid;
1191  }
1192
1193  public static Linear2DSet makeGrid(MapProjection mp, float[][] corners, float res) throws Exception {
1194     float[][] xy = mp.fromReference(corners);
1195
1196     float min_x = Float.MAX_VALUE;
1197     float min_y = Float.MAX_VALUE;
1198     float max_x = -Float.MAX_VALUE;
1199     float max_y = -Float.MAX_VALUE;
1200
1201     for (int k=0; k<xy[0].length;k++) {
1202       if (xy[0][k] < min_x) min_x = xy[0][k];
1203       if (xy[1][k] < min_y) min_y = xy[1][k];
1204       if (xy[0][k] > max_x) max_x = xy[0][k];
1205       if (xy[1][k] > max_y) max_y = xy[1][k];
1206     }
1207
1208     RealType xmap = RealType.getRealType("xmap", CommonUnit.meter);
1209     RealType ymap = RealType.getRealType("ymap", CommonUnit.meter);
1210
1211     RealTupleType rtt = new visad.RealTupleType(xmap, ymap, mp, null);
1212
1213     min_x = ((int) (min_x/res)) * res;
1214     max_x = ((int) (max_x/res)) * res;
1215     min_y = ((int) (min_y/res)) * res;
1216     max_y = ((int) (max_y/res)) * res;
1217
1218     float del_x = max_x - min_x;
1219     float del_y = max_y - min_y;
1220
1221     int xLen = (int) (del_x/res);
1222     int yLen = (int) (del_y/res);
1223
1224     Linear2DSet grid = new Linear2DSet(rtt, min_x, min_x + (xLen-1)*res, xLen,
1225                                             min_y, min_y + (yLen-1)*res, yLen);
1226
1227     return grid;
1228  }
1229
1230
1231  private static int count = 0;
1232
1233  /**
1234   * Resolution of grid should match the loweset of swaths.
1235   * @param  grid  the new domain (target of reproject).
1236   * @param  swaths  one or more swaths to be reprojected.
1237   * @param  mode  See ReprojectSwath for details.
1238   */
1239  public static FlatField swathToGrid(Linear2DSet grid, FlatField[] swaths, double mode) throws Exception {
1240     RealTupleType newRangeType = new RealTupleType(new RealType[] 
1241           {RealType.getRealType("redimage_"+count), RealType.getRealType("greenimage_"+count), RealType.getRealType("blueimage_"+count)});
1242     return swathToGrid(grid, swaths, newRangeType, mode);
1243  }
1244
1245  /**
1246   * Resolution of grid should match the loweset of swaths.
1247   * @param  grid  the new domain (target of reproject).
1248   * @param  swaths  one or more swaths to be reprojected.
1249   * @param  newRangeType user must supply.
1250   * @param  mode  See ReprojectSwath for details.
1251   */
1252  public static FlatField swathToGrid(Linear2DSet grid, FlatField[] swaths, RealTupleType newRangeType, double mode) throws Exception {
1253     int nSwths = swaths.length;
1254     boolean equalDom = true;
1255     for (int k=1; k<nSwths; k++) {
1256        if (!(swaths[0].getDomainSet().equals(swaths[k].getDomainSet()))) {
1257           equalDom = false;
1258           break;
1259        }
1260     }
1261     int tupDim = newRangeType.getNumberOfRealComponents();
1262     float[][] newRangeVals = new float[tupDim][];
1263     if (equalDom) {
1264         FunctionType ftype = (FunctionType) swaths[0].getType();
1265         Gridded2DSet domSet = (Gridded2DSet) swaths[0].getDomainSet();
1266         FlatField swath = new FlatField(new FunctionType(ftype.getDomain(), newRangeType), domSet);
1267         int cnt = 0;
1268         for (int k=0; k<nSwths; k++) {
1269            float[][] rngVals = swaths[k].getFloats(false);
1270            for (int t=0; t<rngVals.length; t++) {
1271                newRangeVals[cnt] = rngVals[t];
1272                cnt++;
1273            }
1274         }
1275         swath.setSamples(newRangeVals, false);
1276         
1277         return swathToGrid(grid, swath, mode);
1278     }
1279     else {
1280         FlatField newGrid = new FlatField(new FunctionType(grid.getType(), newRangeType), grid);
1281         FlatField[] fltFlds = new FlatField[nSwths];
1282         for (int k=0; k<nSwths; k++) {
1283             fltFlds[k] = swathToGrid(grid, swaths[k], mode);
1284         }
1285         int cnt = 0;
1286         for (int k=0; k<nSwths; k++) {
1287            float[][] rngVals = fltFlds[k].getFloats(false);
1288            for (int t=0; t<rngVals.length; t++) {
1289                newRangeVals[cnt] = rngVals[t];
1290                cnt++;
1291            }
1292         }
1293         newGrid.setSamples(newRangeVals, false);
1294         
1295         return newGrid;
1296     }
1297  }
1298
1299  /**
1300   * Grid and swath must both have a CoordinateSystem with an Earth Reference.
1301   * @param  grid  the new domain (target of reproject).
1302   * @param  swath swath to be reprojected.
1303   * @param  mode  See ReprojectSwath for details.
1304   */
1305
1306  public static FlatField swathToGrid(Linear2DSet grid, FlatField swath, double mode) throws Exception {
1307     return ReprojectSwath.swathToGrid(grid, swath, (int)mode);
1308  }
1309
1310  /* keep in here for now.
1311  public static FlatField swathToGrid(Linear2DSet grid, FlatField swath, double mode) throws Exception {
1312    FunctionType ftype = (FunctionType) swath.getType();
1313    Linear2DSet swathDomain = (Linear2DSet) swath.getDomainSet();
1314    int[] lens = swathDomain.getLengths();
1315    float[][] swathRange = swath.getFloats(false);
1316    int trackLen = lens[1];
1317    int xtrackLen = lens[0];
1318    int gridLen = grid.getLength();
1319    lens = grid.getLengths();
1320    int gridXLen = lens[0];
1321    int gridYLen = lens[1];
1322
1323    CoordinateSystem swathCoordSys = swathDomain.getCoordinateSystem();
1324    CoordinateSystem gridCoordSys = grid.getCoordinateSystem();
1325
1326    RealTupleType rtt = ((SetType)grid.getType()).getDomain();
1327    FlatField grdFF = new FlatField(new FunctionType(rtt, ftype.getRange()), grid);
1328    float[][] gridRange = grdFF.getFloats(false);
1329    int rngTupDim = gridRange.length;
1330
1331    float[][] swathGridCoord = new float[2][gridLen];
1332    byte[] numSwathPoints = new byte[gridLen];
1333
1334    int[] swathIndexAtGrid = null;
1335    if (true) {
1336      swathIndexAtGrid = new int[gridLen];
1337    }
1338
1339    float[][] grdCrd = new float[2][1];
1340    float[][] firstGridRange = new float[rngTupDim][gridLen];
1341    float[] sumRange = new float[rngTupDim];
1342    for (int t=0; t<rngTupDim; t++) {
1343       java.util.Arrays.fill(firstGridRange[t], Float.NaN);
1344       java.util.Arrays.fill(gridRange[t], Float.NaN);
1345    }
1346
1347    float g0_last = Float.NaN;
1348    float g1_last = Float.NaN;
1349    float xt_dist = Float.NaN;
1350
1351    for (int j=0; j < trackLen; j++) {
1352       for (int i=0; i < xtrackLen; i++) {
1353         int swathIdx = j*xtrackLen + i;
1354         float val = swathRange[0][swathIdx];
1355
1356         float[][] swathCoord = swathDomain.indexToValue(new int[] {swathIdx});
1357         float[][] swathEarthCoord = swathCoordSys.toReference(swathCoord);
1358
1359         float[][] gridValue = gridCoordSys.fromReference(swathEarthCoord);
1360         float[][] gridCoord = grid.valueToGrid(gridValue);
1361         float g0 = gridCoord[0][0];
1362         float g1 = gridCoord[1][0];
1363         int grdIdx  = (g0 != g0 || g1 != g1) ? -1 : ((int) (g0 + 0.5)) + gridXLen * ((int) (g1 + 0.5));
1364
1365
1366         // tooclose logic
1367         if (i >= 1) {
1368           float diff_0 = g0 - g0_last;
1369           float diff_1 = g1 - g1_last;
1370           xt_dist = (diff_0*diff_0) + (diff_1*diff_1);
1371         }
1372         g0_last = g0;
1373         g1_last = g1;
1374
1375         boolean tooclose = false;
1376         float closest = Float.MAX_VALUE;
1377         for (int n = -2; n < 3; n++) {
1378            for (int m = -2; m < 3; m++) {
1379               int k = grdIdx + (m + n*gridXLen);
1380               if (k >=0 && k < gridXLen*gridYLen) {
1381               if ( !Float.isNaN(swathGridCoord[0][k]) ) {
1382                  float del_0 = g0 - swathGridCoord[0][k];
1383                  float del_1 = g1 - swathGridCoord[1][k];
1384                  float dst = del_0*del_0 + del_1*del_1;
1385                  if (dst < closest) closest = dst;
1386               }
1387               }
1388            }
1389         }
1390         if (Math.sqrt((double)closest) < 0.86*Math.sqrt((double)xt_dist)) tooclose = true;
1391
1392
1393         int m=0;
1394         int n=0;
1395         int k = grdIdx + (m + n*gridXLen);
1396
1397         if ( !(Float.isNaN(val)) && ((k >=0) && (k < gridXLen*gridYLen)) && !tooclose) { // val or val[rngTupDim] ?
1398            float grdVal = firstGridRange[0][k];
1399
1400            if (Float.isNaN(grdVal)) {
1401               for (int t=0; t<rngTupDim; t++) {
1402                  firstGridRange[t][k] = swathRange[t][swathIdx];
1403               }
1404               swathGridCoord[0][k] = g0;
1405               swathGridCoord[1][k] = g1;
1406               swathIndexAtGrid[k] = swathIdx;
1407            }
1408         }
1409
1410       }
1411    }
1412
1413    float[][] gCoord = new float[2][1];
1414    if (mode > 0.0) {  // 2nd pass weighted average
1415    float sigma = 0.6f;
1416    float weight = 1f;
1417    float[] sumValue = new float[rngTupDim];
1418
1419    float[][] dst_sqrd = new float[5][5];
1420    for (int n=-2; n<3; n++) {
1421      for (int m=-2; m<3; m++) {
1422          float del_0 = m;
1423          float del_1 = n;
1424          dst_sqrd[n+2][m+2] = (float) Math.sqrt((double)(del_0*del_0 + del_1*del_1));
1425      }
1426    }
1427   
1428
1429    for (int j=2; j<gridYLen-2; j++) {
1430       for (int i=2; i<gridXLen-2; i++) {
1431         int grdIdx = i + j*gridXLen;
1432
1433         // don't do weighted average if a nearest neigbhor existed for the grid point
1434         if (mode == 2.0) {
1435           if (!Float.isNaN(firstGridRange[0][grdIdx])) {
1436              for (int t=0; t<rngTupDim; t++) {
1437                 gridRange[t][grdIdx] = firstGridRange[t][grdIdx];
1438              }
1439              continue;
1440           }
1441         }
1442
1443         int num = 0;
1444         float mag = 1f;
1445         float sumWeights = 0f;
1446         float[] dists = new float[25];
1447         float[][] values = new float[rngTupDim][25];
1448         for (int t=0; t<rngTupDim; t++) {
1449            sumValue[t] = 0f;
1450         }
1451
1452         for (int n = -1; n < 2; n++) {
1453            for (int m = -1; m < 2; m++) {
1454               int k = grdIdx + (m + n*gridXLen);
1455               if ( !Float.isNaN(firstGridRange[0][k]) ) {
1456                  dists[num] = dst_sqrd[n+2][m+2];
1457                  for (int t=0; t<rngTupDim; t++) {
1458                    values[t][num] = firstGridRange[t][k];
1459                  }
1460                  num++;
1461               }
1462            }
1463         }
1464
1465         if (num < 5) {
1466
1467         for (int n = -2; n < 3; n++) {
1468            for (int m = -2; m < 3; m++) {
1469               if ( (n == -2 || n == 2) || ((n <= 1 && n >= -1) && (m==-2 || m==2)) ) { // don't repeat inner box
1470               int k = grdIdx + (m + n*gridXLen);
1471               if ( !Float.isNaN(firstGridRange[0][k]) ) {
1472                  dists[num] = dst_sqrd[n+2][m+2];
1473                  for (int t=0; t<rngTupDim; t++) {
1474                    values[t][num] = firstGridRange[t][k];
1475                  }
1476                  num++;
1477               }
1478              }
1479            }
1480          }
1481
1482          if (num > 14 && num <= 21) sigma = 0.46f;
1483          if (num > 10 && num <= 14) sigma = 0.50f;
1484          if (num > 7 && num <= 10) sigma = 0.58f;
1485          if (num > 4 && num <= 7) sigma = 0.72f;
1486          if (num < 4) sigma = 1.44f;
1487          }
1488          else { // inner box only
1489            sigma = 0.40f;
1490          }
1491
1492          for (int q=0; q<num; q++) {
1493                float dstsqrd = dists[q];
1494                weight = (float) (mag/Math.exp((double)(dstsqrd/(sigma))));
1495                for (int t=0; t<rngTupDim; t++) {
1496                   sumValue[t] += values[t][q]*weight;
1497                }
1498                sumWeights += weight;
1499          }
1500
1501          for (int t=0; t<rngTupDim; t++) {
1502            gridRange[t][grdIdx] = sumValue[t]/sumWeights;
1503          }
1504
1505        }
1506      }
1507      grdFF.setSamples(gridRange);
1508    }
1509    else { // no averaging
1510      grdFF.setSamples(firstGridRange);
1511    }
1512
1513   return grdFF;
1514 }
1515 */
1516
1517 public static boolean validLonLat(float[][] lonlat) {
1518   float lon = lonlat[0][0];
1519   float lat = lonlat[1][0];
1520   return ((lon >= -180f && lon <= 360f) && (lat >= -90f && lat <= 90f));
1521 }
1522
1523}
1524
1525
1526class ChannelSelection extends DataSelectionComponent {
1527
1528  DataChoice dataChoice;
1529  MultiSpectralDisplay display;
1530
1531  ChannelSelection(DataChoice dataChoice) throws Exception {
1532     super("Channels");
1533     this.dataChoice = dataChoice;
1534     display = new MultiSpectralDisplay((DirectDataChoice)dataChoice);
1535     display.showChannelSelector();
1536  }
1537
1538  protected JComponent doMakeContents() {
1539    try {
1540      JPanel panel = new JPanel(new BorderLayout());
1541      panel.add("Center", display.getDisplayComponent());
1542      if (display.getBandSelectComboBox() != null) {
1543        JPanel bandPanel = new JPanel(new FlowLayout());
1544        bandPanel.add(new JLabel("Band: "));
1545        bandPanel.add(display.getBandSelectComboBox());
1546        panel.add("South", bandPanel);
1547      }
1548      return panel;
1549    }
1550    catch (Exception e) {
1551      System.out.println(e);
1552    }
1553    return null;
1554  }
1555
1556  public void applyToDataSelection(DataSelection dataSelection) {
1557      try {
1558        dataSelection.putProperty(Constants.PROP_CHAN, display.getWaveNumber());
1559        dataSelection.putProperty(SpectrumAdapter.channelIndex_name, display.getChannelIndex());
1560      } catch (Exception e) {
1561        e.printStackTrace();
1562      }
1563  }
1564}
1565
1566class ImageChannelSelection extends DataSelectionComponent {
1567   PreviewSelection previewSelection;
1568   ChannelSelection channelSelection;
1569
1570   ImageChannelSelection(PreviewSelection previewSelection, ChannelSelection channelSelection) {
1571     super("MultiSpectral");
1572     this.previewSelection = previewSelection;
1573     this.channelSelection = channelSelection;
1574   }
1575
1576   protected JComponent doMakeContents() {
1577      JSplitPane splitpane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
1578      splitpane.add(previewSelection.doMakeContents());
1579      splitpane.add(channelSelection.doMakeContents());
1580      splitpane.setContinuousLayout(true);
1581      splitpane.setOneTouchExpandable(true);
1582      splitpane.setResizeWeight(1);
1583      splitpane.setDividerSize(12);
1584      return splitpane;
1585   }
1586
1587   public void applyToDataSelection(DataSelection dataSelection) {
1588     previewSelection.applyToDataSelection(dataSelection);
1589     channelSelection.applyToDataSelection(dataSelection);
1590   }
1591
1592
1593}