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