001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2015
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.Color;
033import java.awt.FlowLayout;
034import java.awt.event.ActionEvent;
035import java.awt.event.ActionListener;
036import java.io.File;
037import java.net.URL;
038import java.rmi.RemoteException;
039import java.util.Enumeration;
040import java.util.HashMap;
041import java.util.Hashtable;
042import java.util.List;
043
044import javax.swing.JComponent;
045import javax.swing.JLabel;
046import javax.swing.JPanel;
047import javax.swing.JTextField;
048
049import visad.CellImpl;
050import visad.Data;
051import visad.FlatField;
052import visad.Gridded2DSet;
053import visad.GriddedSet;
054import visad.RealTupleType;
055import visad.RealType;
056import visad.SampledSet;
057import visad.UnionSet;
058import visad.VisADException;
059import visad.data.mcidas.BaseMapAdapter;
060import visad.georef.MapProjection;
061import ucar.unidata.data.DataCategory;
062import ucar.unidata.data.DataChoice;
063import ucar.unidata.data.DataSelection;
064import ucar.unidata.data.DataSelectionComponent;
065import ucar.unidata.data.DataSourceDescriptor;
066import ucar.unidata.data.DirectDataChoice;
067import ucar.unidata.data.GeoLocationInfo;
068import ucar.unidata.data.GeoSelection;
069import ucar.unidata.geoloc.projection.LatLonProjection;
070import ucar.unidata.util.Misc;
071import ucar.unidata.view.geoloc.MapProjectionDisplay;
072import ucar.unidata.view.geoloc.MapProjectionDisplayJ3D;
073import ucar.visad.ProjectionCoordinateSystem;
074import ucar.visad.display.DisplayMaster;
075import ucar.visad.display.LineDrawing;
076import ucar.visad.display.MapLines;
077import ucar.visad.display.RubberBandBox;
078
079import edu.wisc.ssec.mcidasv.data.HydraDataSource;
080import edu.wisc.ssec.mcidasv.data.PreviewSelection;
081
082/**
083 * A data source for Multi Dimension Data 
084 */
085
086public class MultiDimensionDataSource extends HydraDataSource {
087        
088    /** Sources file */
089    protected String filename;
090
091    protected MultiDimensionReader reader;
092
093    protected MultiDimensionAdapter[] adapters = null;
094    protected HashMap[] defaultSubsets = null;
095    private HashMap<String, MultiDimensionAdapter> adapterMap = new HashMap<String, MultiDimensionAdapter>();
096    protected Hashtable[] propsArray = null;
097    protected List[] categoriesArray = null;
098
099
100    protected SpectrumAdapter spectrumAdapter;
101
102    private static final String DATA_DESCRIPTION = "Multi Dimension Data";
103
104    private HashMap defaultSubset;
105    public TrackAdapter track_adapter;
106    private MultiSpectralData multiSpectData;
107
108    private List categories;
109    private boolean hasImagePreview = false;
110    private boolean hasTrackPreview = false;
111
112    /**
113     * Zero-argument constructor for construction via unpersistence.
114     */
115    public MultiDimensionDataSource() {}
116
117    /**
118     * Construct a new HYDRA hdf data source.
119     * @param  descriptor  descriptor for this {@code DataSource}
120     * @param  fileName  name of the hdf file to read
121     * @param  properties  hashtable of properties
122     *
123     * @throws VisADException problem creating data
124     */
125    public MultiDimensionDataSource(DataSourceDescriptor descriptor,
126                                 String fileName, Hashtable properties)
127            throws VisADException {
128        this(descriptor, Misc.newList(fileName), properties);
129    }
130
131    /**
132     * Construct a new HYDRA hdf data source.
133     * @param  descriptor  descriptor for this {@code DataSource}
134     * @param  newSources  List of filenames
135     * @param  properties  hashtable of properties
136     *
137     * @throws VisADException problem creating data
138     */
139    public MultiDimensionDataSource(DataSourceDescriptor descriptor,
140                                 List newSources, Hashtable properties)
141            throws VisADException {
142        super(descriptor, newSources, DATA_DESCRIPTION, properties);
143
144        this.filename = (String)sources.get(0);
145
146        try {
147          setup();
148        }
149        catch (Exception e) {
150          e.printStackTrace();
151          throw new VisADException();
152        }
153    }
154
155    public void setup() throws Exception {
156
157        try {
158          if (filename.contains("MYD02SSH")) { // get file union
159            String other = (String) sources.get(1);
160            if (filename.endsWith("nav.hdf")) {
161              String tmp = filename;
162              filename = other;
163              other = tmp;
164            }
165            reader = NetCDFFile.makeUnion(filename, other);
166          }
167          else {
168            reader = new NetCDFFile(filename);
169          }
170        }
171        catch (Exception e) {
172          e.printStackTrace();
173          System.out.println("cannot create NetCDF reader for file: "+filename);
174        }
175
176        adapters = new MultiDimensionAdapter[2];
177        defaultSubsets = new HashMap[2]; 
178        Hashtable<String, String[]> properties = new Hashtable<String, String[]>(); 
179        
180        String name = (new File(filename)).getName();
181
182        if ( name.startsWith("MOD04") || name.startsWith("MYD04")) {
183          HashMap table = SwathAdapter.getEmptyMetadataTable();
184          table.put("array_name", "mod04/Data_Fields/Optical_Depth_Land_And_Ocean");
185          table.put("lon_array_name", "mod04/Geolocation_Fields/Longitude");
186          table.put("lat_array_name", "mod04/Geolocation_Fields/Latitude");
187          table.put("XTrack", "Cell_Across_Swath");
188          table.put("Track", "Cell_Along_Swath");
189          table.put("geo_Track", "Cell_Along_Swath");
190          table.put("geo_XTrack", "Cell_Across_Swath");
191          table.put("scale_name", "scale_factor");
192          table.put("offset_name", "add_offset");
193          table.put("fill_value_name", "_FillValue");
194          table.put("range_name", "Optical_Depth_Land_And_Ocean");
195          adapters[0] = new SwathAdapter(reader, table);
196          categories = DataCategory.parseCategories("2D grid;GRID-2D;");
197          defaultSubset = adapters[0].getDefaultSubset();
198          defaultSubsets[0] = defaultSubset;
199        }
200        else if ( name.startsWith("MOD06") || name.startsWith("MYD06")) {
201          hasImagePreview = true;
202          String path = "mod06/Data_Fields/";
203          String[] arrayNames = new String[] {"Cloud_Optical_Thickness", "Cloud_Effective_Radius", "Cloud_Water_Path"};
204          String[] arrayNames_5km = new String[] {"Cloud_Top_Pressure", "Cloud_Top_Temperature", "Cloud_Fraction"};
205  
206          adapters = new MultiDimensionAdapter[arrayNames.length+arrayNames_5km.length];
207          defaultSubsets = new HashMap[arrayNames.length+arrayNames_5km.length];
208          categoriesArray = new List[adapters.length];
209
210          
211          for (int k=0; k<arrayNames.length; k++) {
212            HashMap table = SwathAdapter.getEmptyMetadataTable();
213            table.put("array_name", path.concat(arrayNames[k]));
214            table.put("lon_array_name", "mod06/Geolocation_Fields/Longitude");
215            table.put("lat_array_name", "mod06/Geolocation_Fields/Latitude");
216            table.put("XTrack", "Cell_Across_Swath_1km");
217            table.put("Track", "Cell_Along_Swath_1km");
218            table.put("geo_Track", "Cell_Along_Swath_5km");
219            table.put("geo_XTrack", "Cell_Across_Swath_5km");
220            table.put("scale_name", "scale_factor");
221            table.put("offset_name", "add_offset");
222            table.put("fill_value_name", "_FillValue");
223            table.put("range_name", arrayNames[k]);
224
225            table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
226            table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
227            table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
228            table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0148148148));
229
230            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
231            swathAdapter.setDefaultStride(10);
232            defaultSubset = swathAdapter.getDefaultSubset();
233            adapters[k] = swathAdapter;
234            defaultSubsets[k] = defaultSubset;
235            categoriesArray[k] = DataCategory.parseCategories("1km swath;GRID-2D;");
236          }
237
238          for (int k=0; k<arrayNames_5km.length; k++) {
239            HashMap table = SwathAdapter.getEmptyMetadataTable();
240            table.put("array_name", path.concat(arrayNames_5km[k]));
241            table.put("lon_array_name", "mod06/Geolocation_Fields/Longitude");
242            table.put("lat_array_name", "mod06/Geolocation_Fields/Latitude");
243            table.put("XTrack", "Cell_Across_Swath_5km");
244            table.put("Track", "Cell_Along_Swath_5km");
245            table.put("geo_Track", "Cell_Along_Swath_5km");
246            table.put("geo_XTrack", "Cell_Across_Swath_5km");
247            table.put("scale_name", "scale_factor");
248            table.put("offset_name", "add_offset");
249            table.put("fill_value_name", "_FillValue");
250            table.put("range_name", arrayNames_5km[k]);
251
252            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
253            defaultSubset = swathAdapter.getDefaultSubset();
254            adapters[arrayNames.length+k] = swathAdapter;
255            defaultSubsets[arrayNames.length+k] = defaultSubset;
256            categoriesArray[arrayNames.length+k] = DataCategory.parseCategories("5km swath;GRID-2D;");
257          }
258       }
259       else if (name.startsWith("a1") && name.contains("mod06")) {
260          hasImagePreview = true;
261          String[] arrayNames = new String[] {"Cloud_Optical_Thickness", "Cloud_Effective_Radius", "Cloud_Water_Path"};
262          String[] arrayNames_5km = new String[] {"Cloud_Top_Pressure", "Cloud_Top_Temperature", "Cloud_Fraction"};
263
264          adapters = new MultiDimensionAdapter[arrayNames.length+arrayNames_5km.length];
265          defaultSubsets = new HashMap[arrayNames.length+arrayNames_5km.length];
266          categoriesArray = new List[adapters.length];
267
268
269          for (int k=0; k<arrayNames.length; k++) {
270            HashMap table = SwathAdapter.getEmptyMetadataTable();
271            table.put("array_name", arrayNames[k]);
272            table.put("lon_array_name", "Longitude");
273            table.put("lat_array_name", "Latitude");
274            table.put("array_dimension_names", new String[] {"Cell_Along_Swath_1km", "Cell_Across_Swath_1km"});
275            table.put("lon_array_dimension_names", new String[] {"Cell_Along_Swath_1km", "Cell_Across_Swath_1km"});
276            table.put("lat_array_dimension_names", new String[] {"Cell_Along_Swath_1km", "Cell_Across_Swath_1km"});
277            table.put("XTrack", "Cell_Across_Swath_1km");
278            table.put("Track", "Cell_Along_Swath_1km");
279            table.put("geo_Track", "Cell_Along_Swath_5km");
280            table.put("geo_XTrack", "Cell_Across_Swath_5km");
281            table.put("scale_name", "scale_factor");
282            table.put("offset_name", "add_offset");
283            table.put("fill_value_name", "_FillValue");
284            table.put("range_name", arrayNames[k]);
285
286            table.put(SwathAdapter.geo_track_offset_name, Double.toString(2.0));
287            table.put(SwathAdapter.geo_xtrack_offset_name, Double.toString(2.0));
288            table.put(SwathAdapter.geo_track_skip_name, Double.toString(5.0));
289            table.put(SwathAdapter.geo_xtrack_skip_name, Double.toString(5.0148148148));
290
291            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
292            swathAdapter.setDefaultStride(10);
293            defaultSubset = swathAdapter.getDefaultSubset();
294            adapters[k] = swathAdapter;
295            defaultSubsets[k] = defaultSubset;
296            categoriesArray[k] = DataCategory.parseCategories("1km swath;GRID-2D;");
297          }
298
299          for (int k=0; k<arrayNames_5km.length; k++) {
300            HashMap table = SwathAdapter.getEmptyMetadataTable();
301            table.put("array_name", arrayNames_5km[k]);
302            table.put("lon_array_name", "Longitude");
303            table.put("lat_array_name", "Latitude");
304            table.put("array_dimension_names", new String[] {"Cell_Along_Swath_5km", "Cell_Across_Swath_5km"});
305            table.put("lon_array_dimension_names", new String[] {"Cell_Along_Swath_5km", "Cell_Across_Swath_5km"});
306            table.put("lat_array_dimension_names", new String[] {"Cell_Along_Swath_5km", "Cell_Across_Swath_5km"});
307            table.put("XTrack", "Cell_Across_Swath_5km");
308            table.put("Track", "Cell_Along_Swath_5km");
309            table.put("geo_Track", "Cell_Along_Swath_5km");
310            table.put("geo_XTrack", "Cell_Across_Swath_5km");
311            table.put("scale_name", "scale_factor");
312            table.put("offset_name", "add_offset");
313            table.put("fill_value_name", "_FillValue");
314            table.put("range_name", arrayNames_5km[k]);
315
316            SwathAdapter swathAdapter = new SwathAdapter(reader, table);
317            defaultSubset = swathAdapter.getDefaultSubset();
318            adapters[arrayNames.length+k] = swathAdapter;
319            defaultSubsets[arrayNames.length+k] = defaultSubset;
320            categoriesArray[arrayNames.length+k] = DataCategory.parseCategories("5km swath;GRID-2D;");
321          }
322       }
323       else if (name.startsWith("CAL_LID_L1")) {
324         String[] arrayNames = null;
325         adapters = new MultiDimensionAdapter[4];
326         defaultSubsets = new HashMap[4];
327         propsArray = new Hashtable[4]; 
328         
329         
330         HashMap table = ProfileAlongTrack.getEmptyMetadataTable();
331         table.put(ProfileAlongTrack.array_name, "Total_Attenuated_Backscatter_532");
332         table.put(ProfileAlongTrack.ancillary_file_name, "/edu/wisc/ssec/mcidasv/data/hydra/resources/calipso/altitude");
333         table.put(ProfileAlongTrack.trackDim_name, "dim0");
334         table.put(ProfileAlongTrack.vertDim_name, "dim1");
335         table.put(ProfileAlongTrack.profileTime_name, "Profile_Time");
336         table.put(ProfileAlongTrack.longitude_name, "Longitude");
337         table.put(ProfileAlongTrack.latitude_name, "Latitude");
338         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
339         ProfileAlongTrack adapter = new Calipso2D(reader, table);
340         ProfileAlongTrack3D adapter3D = new ProfileAlongTrack3D(adapter);
341         HashMap subset = adapter.getDefaultSubset();
342         adapters[0] = adapter3D;
343         defaultSubset = subset;
344         defaultSubsets[0] = defaultSubset;
345         DataCategory.createCategory("ProfileAlongTrack");
346         categories = DataCategory.parseCategories("ProfileAlongTrack;ProfileAlongTrack;");
347
348         properties.put("medianFilter", new String[] {Double.toString(8), Double.toString(16)});
349         properties.put("setBelowSfcMissing", new String[] {"true"});
350         propsArray[0] = properties;
351
352
353         ArrayAdapter[] adapter_s = new ArrayAdapter[3];
354         table = ProfileAlongTrack.getEmptyMetadataTable();
355         table.put(ProfileAlongTrack.array_name, "Latitude");
356         table.put(ProfileAlongTrack.trackDim_name, "dim0");
357         table.put(ProfileAlongTrack.vertDim_name, "dim1");
358         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
359         adapter_s[0] = new ArrayAdapter(reader, table);
360
361         table = ProfileAlongTrack.getEmptyMetadataTable();
362         table.put(ProfileAlongTrack.array_name, "Surface_Elevation");
363         table.put(ProfileAlongTrack.trackDim_name, "dim0");
364         table.put(ProfileAlongTrack.vertDim_name, "dim1");
365         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
366         adapter_s[1] = new ArrayAdapter(reader, table);
367
368         table = ProfileAlongTrack.getEmptyMetadataTable();
369         table.put(ProfileAlongTrack.array_name, "Longitude");
370         table.put(ProfileAlongTrack.trackDim_name, "dim0");
371         table.put(ProfileAlongTrack.vertDim_name, "dim1");
372         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
373         adapter_s[2] = new ArrayAdapter(reader, table);
374
375         TrackDomain track_domain = new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]);
376         track_adapter = new TrackAdapter(track_domain, adapter_s[1]);
377
378         table = ProfileAlongTrack.getEmptyMetadataTable();
379         table.put(ProfileAlongTrack.array_name, "Tropopause_Height");
380         table.put(ProfileAlongTrack.trackDim_name, "dim0");
381         table.put(ProfileAlongTrack.vertDim_name, "dim1");
382         table.put("array_dimension_names", new String[] {"dim0", "dim1"}); 
383         ArrayAdapter trop_height = new ArrayAdapter(reader, table);
384         track_domain = new TrackDomain(adapter_s[2], adapter_s[0], trop_height);
385         adapters[1] = new TrackAdapter(track_domain, trop_height);
386         defaultSubsets[1] = adapters[1].getDefaultSubset();
387
388         adapters[2] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]), adapter_s[1]);
389         ((TrackAdapter)adapters[2]).setName("Track3D");
390         defaultSubsets[2] = adapters[2].getDefaultSubset();
391
392         adapters[3] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0]), adapter_s[1]);
393         ((TrackAdapter)adapters[3]).setName("Track2D");
394         defaultSubsets[3] = adapters[3].getDefaultSubset();
395         
396
397         hasTrackPreview = true;
398       }
399       else if (name.startsWith("CAL_LID_L2")) {
400         adapters = new MultiDimensionAdapter[4];
401         defaultSubsets = new HashMap[4];
402         propsArray = new Hashtable[4];
403
404         ArrayAdapter[] adapter_s = new ArrayAdapter[3];
405
406         HashMap table = ProfileAlongTrack.getEmptyMetadataTable();
407         table.put(ProfileAlongTrack.array_name, "Longitude");
408         table.put(ProfileAlongTrack.trackDim_name, "dim0");
409         table.put(ProfileAlongTrack.vertDim_name, "dim1");
410         adapter_s[0] = new ArrayAdapter(reader, table);
411
412         table = ProfileAlongTrack.getEmptyMetadataTable();
413         table.put(ProfileAlongTrack.array_name, "Latitude");
414         table.put(ProfileAlongTrack.trackDim_name, "dim0");
415         table.put(ProfileAlongTrack.vertDim_name, "dim1");
416         adapter_s[1] = new ArrayAdapter(reader, table);
417
418         table = ProfileAlongTrack.getEmptyMetadataTable();
419         table.put(ProfileAlongTrack.array_name, "DEM_Surface_Elevation");
420         table.put(ProfileAlongTrack.trackDim_name, "dim0");
421         table.put(ProfileAlongTrack.vertDim_name, "dim1");
422         adapter_s[2] = new ArrayAdapter(reader, table);
423
424         TrackDomain track_domain = new TrackDomain(adapter_s[0], adapter_s[1], adapter_s[2]);
425         track_adapter = new TrackAdapter(track_domain, adapter_s[2]);
426         adapters[1] = track_adapter;
427         defaultSubsets[1] = track_adapter.getDefaultSubset();
428
429         table = ProfileAlongTrack.getEmptyMetadataTable();
430         table.put(ProfileAlongTrack.array_name, "Layer_Top_Altitude");
431         table.put(ProfileAlongTrack.trackDim_name, "dim0");
432         table.put(ProfileAlongTrack.vertDim_name, "dim1");
433         ArrayAdapter layer_top_altitude = new ArrayAdapter(reader, table);
434         RangeProcessor rngProcessor =
435             new RangeProcessor(1.0f, 0.0f, -Float.MAX_VALUE, Float.MAX_VALUE, -9999.0f);
436         layer_top_altitude.setRangeProcessor(rngProcessor);
437
438         track_domain = new TrackDomain(adapter_s[0], adapter_s[1], layer_top_altitude);
439         adapters[0] = new TrackAdapter(track_domain, layer_top_altitude);
440         defaultSubsets[0] = adapters[0].getDefaultSubset();
441
442         /** another layer, how to show all?
443         adapters[2] = new TrackAdapter(track_domain, layer_top_altitude);
444         ((TrackAdapter)adapters[2]).setListIndex(1);
445         defaultSubsets[2] = adapters[2].getDefaultSubset();
446         */
447
448         adapters[2] = new TrackAdapter(new TrackDomain(adapter_s[0], adapter_s[1]), adapter_s[2]);
449         ((TrackAdapter)adapters[2]).setName("Track2D");
450         defaultSubsets[2] = adapters[2].getDefaultSubset();
451
452         adapters[3] = new TrackAdapter(new TrackDomain(adapter_s[0], adapter_s[1], adapter_s[2]), adapter_s[2]);
453         ((TrackAdapter)adapters[3]).setName("Track3D");
454         defaultSubsets[3] = adapters[3].getDefaultSubset();
455
456         DataCategory.createCategory("ProfileAlongTrack");
457         categories = DataCategory.parseCategories("ProfileAlongTrack;ProfileAlongTrack;");
458
459         hasTrackPreview = true;
460       }
461       else if (name.indexOf("2B-GEOPROF") > 0) {
462         adapters = new MultiDimensionAdapter[2];
463         defaultSubsets = new HashMap[2];
464         propsArray = new Hashtable[2];
465
466         HashMap table = ProfileAlongTrack.getEmptyMetadataTable();
467         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Data_Fields/Radar_Reflectivity");
468         table.put(ProfileAlongTrack.range_name, "2B-GEOPROF_RadarReflectivity");
469         table.put(ProfileAlongTrack.scale_name, "factor");
470         table.put(ProfileAlongTrack.offset_name, "offset");
471         table.put(ProfileAlongTrack.fill_value_name, "_FillValue");
472         table.put(ProfileAlongTrack.valid_range, "valid_range");
473         table.put(ProfileAlongTrack.ancillary_file_name, "/edu/wisc/ssec/mcidasv/data/hydra/resources/cloudsat/altitude");
474         table.put(ProfileAlongTrack.trackDim_name, "nray");
475         table.put(ProfileAlongTrack.vertDim_name, "nbin");
476         table.put(ProfileAlongTrack.profileTime_name, "2B-GEOPROF/Geolocation_Fields/Profile_Time");
477         table.put(ProfileAlongTrack.longitude_name, "2B-GEOPROF/Geolocation_Fields/Longitude");
478         table.put(ProfileAlongTrack.latitude_name, "2B-GEOPROF/Geolocation_Fields/Latitude");
479         table.put(ProfileAlongTrack.product_name, "2B-GEOPROF");
480         ProfileAlongTrack adapter = new CloudSat2D(reader, table);
481         ProfileAlongTrack3D adapter3D = new ProfileAlongTrack3D(adapter);
482         HashMap subset = adapter.getDefaultSubset();
483         adapters[0] = adapter3D;
484         defaultSubset = subset;
485         defaultSubsets[0] = defaultSubset;
486         DataCategory.createCategory("ProfileAlongTrack");
487         categories = DataCategory.parseCategories("ProfileAlongTrack;ProfileAlongTrack;");
488
489         ArrayAdapter[] adapter_s = new ArrayAdapter[3];
490         table = ProfileAlongTrack.getEmptyMetadataTable();
491         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Geolocation_Fields/Latitude");
492         table.put(ProfileAlongTrack.range_name, "Latitude");
493         table.put(ProfileAlongTrack.trackDim_name, "nray");
494         adapter_s[0] = new ArrayAdapter(reader, table);
495
496         table = ProfileAlongTrack.getEmptyMetadataTable();
497         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Geolocation_Fields/DEM_elevation");
498         table.put(ProfileAlongTrack.range_name, "DEM_elevation");
499         table.put(ProfileAlongTrack.trackDim_name, "nray");
500         adapter_s[1] = new ArrayAdapter(reader, table);
501
502         table = ProfileAlongTrack.getEmptyMetadataTable();
503         table.put(ProfileAlongTrack.array_name, "2B-GEOPROF/Geolocation_Fields/Longitude");
504         table.put(ProfileAlongTrack.range_name, "Longitude");
505         table.put(ProfileAlongTrack.trackDim_name, "nray");
506         adapter_s[2] = new ArrayAdapter(reader, table);
507
508         TrackDomain track_domain = new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]);
509         track_adapter = new TrackAdapter(track_domain, adapter_s[1]);
510
511         /*
512         adapters[2] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0], adapter_s[1]), adapter_s[1]);
513         ((TrackAdapter)adapters[2]).setName("Track3D");
514         defaultSubsets[2] = adapters[2].getDefaultSubset();
515         */
516
517         adapters[1] = new TrackAdapter(new TrackDomain(adapter_s[2], adapter_s[0]), adapter_s[1]);
518         ((TrackAdapter)adapters[1]).setName("Track2D");
519         defaultSubsets[1] = adapters[1].getDefaultSubset();
520
521
522         properties.put("medianFilter", new String[] {Double.toString(6), Double.toString(14)});
523         properties.put("setBelowSfcMissing", new String[] {"true"});
524         hasTrackPreview = true;
525       }
526       else if ( name.startsWith("MHSx_xxx_1B") && name.endsWith("h5")) {
527          HashMap table = SwathAdapter.getEmptyMetadataTable();
528          table.put("array_name", "U-MARF/EPS/MHSx_xxx_1B/DATA/Channel1");
529          table.put("lon_array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/IMAGE_LON_ARRAY");
530          table.put("lat_array_name", "U-MARF/EPS/IASI_xxx_1C/DATA/IMAGE_LAT_ARRAY");
531          table.put("XTrack", "dim1");
532          table.put("Track", "dim0");
533          table.put("geo_XTrack", "dim1");
534          table.put("geo_Track", "dim0");
535          table.put("product_name", "MHSx_xxx_1B");
536          SwathAdapter swathAdapter = new SwathAdapter(reader, table);
537          adapters[0] = swathAdapter;
538          HashMap subset = swathAdapter.getDefaultSubset();
539          defaultSubset = subset;
540          defaultSubsets[0] = defaultSubset;
541          categories = DataCategory.parseCategories("2D grid;GRID-2D;");
542       }
543       else if ( name.startsWith("MYD02SSH") ) {
544         String[] arrayNames = null;
545
546         if (name.endsWith("level2.hdf")) {
547           arrayNames = new String[] {"cld_press_acha", "cld_temp_acha", "cld_height_acha", "cloud_type",
548                                             "cloud_albedo_0_65um_nom", "cloud_transmission_0_65um_nom", "cloud_fraction"};
549         }
550         else if (name.endsWith("obs.hdf")) {
551           arrayNames = new String[] {"refl_0_65um_nom", "refl_0_86um_nom", "refl_3_75um_nom", "refl_1_60um_nom", "refl_1_38um_nom",
552                                      "temp_3_75um_nom", "temp_11_0um_nom", "temp_12_0um_nom", "temp_6_7um_nom",
553                                      "temp_8_5um_nom", "temp_13_3um_nom"};
554         }
555  
556         adapters = new MultiDimensionAdapter[arrayNames.length];
557         defaultSubsets = new HashMap[arrayNames.length];
558         propsArray = new Hashtable[arrayNames.length]; 
559
560         for (int k=0; k<arrayNames.length; k++) {
561           HashMap swthTable = SwathAdapter.getEmptyMetadataTable();
562           swthTable.put("array_name", arrayNames[k]);
563           swthTable.put("lon_array_name", "pixel_longitude");
564           swthTable.put("lat_array_name", "pixel_latitude");
565           swthTable.put("XTrack", "pixel_elements_along_scan_direction");
566           swthTable.put("Track", "scan_lines_along_track_direction");
567           swthTable.put("geo_Track", "scan_lines_along_track_direction");
568           swthTable.put("geo_XTrack", "pixel_elements_along_scan_direction");
569           swthTable.put("scale_name", "SCALE_FACTOR");
570           swthTable.put("offset_name", "ADD_OFFSET");
571           swthTable.put("fill_value_name", "_FILLVALUE");
572           swthTable.put("geo_scale_name", "SCALE_FACTOR");
573           swthTable.put("geo_offset_name", "ADD_OFFSET");
574           swthTable.put("geo_fillValue_name", "_FILLVALUE");
575           swthTable.put("range_name", arrayNames[k]);
576           swthTable.put("unpack", "unpack");
577
578           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
579           HashMap subset = swathAdapter0.getDefaultSubset();
580           defaultSubset = subset;
581           adapters[k] = swathAdapter0;
582           defaultSubsets[k] = defaultSubset;
583         }
584         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
585         hasImagePreview = true;
586       }
587       else if (name.contains("AWG_OZONE") ) {
588         String[] arrayNames = new String[] {"ColumnOzone"};
589
590         adapters = new MultiDimensionAdapter[arrayNames.length];
591         defaultSubsets = new HashMap[arrayNames.length];
592         propsArray = new Hashtable[arrayNames.length];
593         
594         for (int k=0; k<arrayNames.length; k++) {
595           HashMap swthTable = SwathAdapter.getEmptyMetadataTable();
596           swthTable.put("array_name", arrayNames[k]);
597           swthTable.put("lon_array_name", "Longitude");
598           swthTable.put("lat_array_name", "Latitude");
599           swthTable.put("XTrack", "Columns");
600           swthTable.put("Track", "Rows");
601           swthTable.put("fill_value_name", "_FillValue");
602           swthTable.put("geo_Track", "Rows");
603           swthTable.put("geo_XTrack", "Columns");
604           swthTable.put("geo_fillValue_name", "_FillValue");
605           swthTable.put("range_name", arrayNames[k]);
606
607           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
608           swathAdapter0.setDefaultStride(5);
609           HashMap subset = swathAdapter0.getDefaultSubset();
610           defaultSubset = subset;
611           adapters[k] = swathAdapter0;
612           defaultSubsets[k] = defaultSubset;
613         }
614
615         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
616         hasImagePreview = true;
617       }
618       else if (name.contains("AWG_CLOUD_MASK") ) {
619         String[] arrayNames = new String[] {"CloudMask"};
620
621         adapters = new MultiDimensionAdapter[arrayNames.length];
622         defaultSubsets = new HashMap[arrayNames.length];
623         propsArray = new Hashtable[arrayNames.length];
624
625         for (int k=0; k<arrayNames.length; k++) {
626           HashMap swthTable = SwathAdapter.getEmptyMetadataTable();
627           swthTable.put("array_name", arrayNames[k]);
628           swthTable.put("lon_array_name", "Longitude");
629           swthTable.put("lat_array_name", "Latitude");
630           swthTable.put("XTrack", "Columns");
631           swthTable.put("Track", "Rows");
632           swthTable.put("fill_value_name", "_FillValue");
633           swthTable.put("geo_Track", "Rows");
634           swthTable.put("geo_XTrack", "Columns");
635           swthTable.put("geo_fillValue_name", "_FillValue");
636           swthTable.put("range_name", arrayNames[k]);
637
638           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
639           swathAdapter0.setDefaultStride(5);
640           HashMap subset = swathAdapter0.getDefaultSubset();
641           defaultSubset = subset;
642           adapters[k] = swathAdapter0;
643           defaultSubsets[k] = defaultSubset;
644         }
645
646         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
647         hasImagePreview = true;
648       }
649       else if (name.contains("AWG_CLOUD_HEIGHT")) {
650         String[] arrayNames = new String[] {"CldTopTemp", "CldTopPres", "CldTopHght"};
651
652         adapters = new MultiDimensionAdapter[arrayNames.length];
653         defaultSubsets = new HashMap[arrayNames.length];
654         propsArray = new Hashtable[arrayNames.length];
655
656         for (int k=0; k<arrayNames.length; k++) {
657           HashMap swthTable = SwathAdapter.getEmptyMetadataTable();
658           swthTable.put("array_name", arrayNames[k]);
659           swthTable.put("lon_array_name", "Longitude");
660           swthTable.put("lat_array_name", "Latitude");
661           swthTable.put("XTrack", "Columns");
662           swthTable.put("Track", "Rows");
663           swthTable.put("scale_name", "scale_factor");
664           swthTable.put("offset_name", "add_offset");
665           swthTable.put("fill_value_name", "_FillValue");
666           swthTable.put("geo_Track", "Rows");
667           swthTable.put("geo_XTrack", "Columns");
668           swthTable.put("geo_scale_name", "scale_factor");
669           swthTable.put("geo_offset_name", "add_offset");
670           swthTable.put("geo_fillValue_name", "_FillValue");
671           swthTable.put("range_name", arrayNames[k]);
672           swthTable.put("unpack", "unpack");
673
674           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
675           swathAdapter0.setDefaultStride(5);
676           HashMap subset = swathAdapter0.getDefaultSubset();
677           defaultSubset = subset;
678           adapters[k] = swathAdapter0;
679           defaultSubsets[k] = defaultSubset;
680         }
681         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
682         hasImagePreview = true;
683       }
684       else if (name.startsWith("geocatL2") && name.endsWith("ci.hdf")) {
685         String[] arrayNames = new String[] {"box_average_11um_ctc", "box_average_11um_ctc_scaled", "conv_init", "cloud_type"};
686
687         adapters = new MultiDimensionAdapter[arrayNames.length];
688         defaultSubsets = new HashMap[arrayNames.length];
689         propsArray = new Hashtable[arrayNames.length];
690
691         for (int k=0; k<arrayNames.length; k++) {
692           HashMap swthTable = SwathAdapter.getEmptyMetadataTable();
693           swthTable.put("array_name", arrayNames[k]);
694           swthTable.put("lon_array_name", "lon");
695           swthTable.put("lat_array_name", "lat");
696           swthTable.put("XTrack", "Elements");
697           swthTable.put("Track", "Lines");
698           swthTable.put("geo_Track", "Lines");
699           swthTable.put("geo_XTrack", "Elements");
700           swthTable.put("range_name", arrayNames[k]);
701
702           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
703           swathAdapter0.setDefaultStride(1);
704           HashMap subset = swathAdapter0.getDefaultSubset();
705           defaultSubset = subset;
706           adapters[k] = swathAdapter0;
707           defaultSubsets[k] = defaultSubset;
708         }
709         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
710         hasImagePreview = true;
711       } 
712       else {
713         String[] arrayNames = new String[] {"baseline_cmask_seviri_cloud_mask", "baseline_ctype_seviri_cloud_type",
714                                             "baseline_ctype_seviri_cloud_phase", "baseline_cld_hght_seviri_cloud_top_pressure",
715                                             "baseline_cld_hght_seviri_cloud_top_height"};
716
717         adapters = new MultiDimensionAdapter[arrayNames.length];
718         defaultSubsets = new HashMap[arrayNames.length];
719         propsArray = new Hashtable[arrayNames.length]; 
720
721         for (int k=0; k<arrayNames.length; k++) {
722           HashMap swthTable = SwathAdapter.getEmptyMetadataTable();
723           swthTable.put("array_name", arrayNames[k]);
724           swthTable.put("lon_array_name", "pixel_longitude");
725           swthTable.put("lat_array_name", "pixel_latitude");
726           swthTable.put("XTrack", "elements");
727           swthTable.put("Track", "lines");
728           swthTable.put("scale_name", "scale_factor");
729           swthTable.put("offset_name", "add_offset");
730           swthTable.put("fill_value_name", "_FillValue");
731           swthTable.put("geo_Track", "lines");
732           swthTable.put("geo_XTrack", "elements");
733           swthTable.put("geo_scale_name", "scale_factor");
734           swthTable.put("geo_offset_name", "add_offset");
735           swthTable.put("geo_fillValue_name", "_FillValue");
736           swthTable.put("range_name", arrayNames[k]);
737           swthTable.put("unpack", "unpack");
738
739           SwathAdapter swathAdapter0 = new SwathAdapter(reader, swthTable);
740           swathAdapter0.setDefaultStride(2);
741           HashMap subset = swathAdapter0.getDefaultSubset();
742           defaultSubset = subset;
743           adapters[k] = swathAdapter0;
744           defaultSubsets[k] = defaultSubset;
745         }
746         categories = DataCategory.parseCategories("2D grid;GRID-2D;");
747         hasImagePreview = true;
748       }
749
750       setProperties(properties);
751    }
752
753    public void initAfterUnpersistence() {
754      try {
755        setup();
756      } 
757      catch (Exception e) {
758      }
759    }
760
761    /**
762     * Make and insert the {@link DataChoice DataChoices} for this {@code DataSource}.
763     */
764    public void doMakeDataChoices() {
765        DataChoice choice = null;
766        if (adapters != null) {
767          for (int idx=0; idx<adapters.length; idx++) {
768             try {
769               String arrayName = (adapters[idx] == null) ? "_     " : adapters[idx].getArrayName();
770               choice = doMakeDataChoice(idx, arrayName);
771               adapterMap.put(choice.getName(), adapters[idx]);
772             } 
773             catch (Exception e) {
774               e.printStackTrace();
775               System.out.println("doMakeDataChoice failed");
776             }
777
778             if (choice != null) {
779               addDataChoice(choice);
780             }
781          }
782        }
783    }
784
785    private DataChoice doMakeDataChoice(int idx, String var) throws Exception {
786        String name = var;
787        DataSelection dataSel = (defaultSubsets[idx] == null) ? new MultiDimensionSubset() : new MultiDimensionSubset(defaultSubsets[idx]);
788        Hashtable props = new Hashtable();
789        props.put(new MultiDimensionSubset(), dataSel);
790
791        if (propsArray != null) {
792          if (propsArray[idx] != null) {
793            propsArray[idx].put(new MultiDimensionSubset(), dataSel);
794            props = propsArray[idx];
795          }
796        }
797        DirectDataChoice ddc = null;
798
799        if (categories != null) {
800           ddc = new DirectDataChoice(this, idx, name, name, categories, props);
801        }
802        else {
803           ddc = new DirectDataChoice(this, idx, name, name, categoriesArray[idx], props);
804        }
805
806        return ddc;
807    }
808
809    /**
810     * Check to see if this {@code HDFHydraDataSource} is equal to the object
811     * in question.
812     * @param o  object in question
813     * @return true if they are the same or equivalent objects
814     */
815    public boolean equals(Object o) {
816        if ( !(o instanceof MultiDimensionDataSource)) {
817            return false;
818        }
819        return (this == (MultiDimensionDataSource) o);
820    }
821
822    public MultiSpectralData getMultiSpectralData() {
823      return multiSpectData;
824    }
825
826    public String getDatasetName() {
827      return filename;
828    }
829
830    public void setDatasetName(String name) {
831      filename = name;
832    }
833
834    public HashMap getSubsetFromLonLatRect(MultiDimensionSubset select, GeoSelection geoSelection) {
835      GeoLocationInfo ginfo = geoSelection.getBoundingBox();
836      return adapters[0].getSubsetFromLonLatRect(select.getSubset(), ginfo.getMinLat(), ginfo.getMaxLat(),
837                                        ginfo.getMinLon(), ginfo.getMaxLon());
838    }
839
840    public synchronized Data getData(DataChoice dataChoice, DataCategory category,
841                                DataSelection dataSelection, Hashtable requestProperties)
842                                throws VisADException, RemoteException {
843       return this.getDataInner(dataChoice, category, dataSelection, requestProperties);
844    }
845
846
847    protected Data getDataInner(DataChoice dataChoice, DataCategory category,
848                                DataSelection dataSelection, Hashtable requestProperties)
849                                throws VisADException, RemoteException {
850
851        MultiDimensionAdapter adapter = null;
852        adapter = adapterMap.get(dataChoice.getName());
853
854        Hashtable dataChoiceProps = dataChoice.getProperties();
855
856        //- this hack keeps the HydraImageProbe from doing a getData()
857        //- TODO: need to use categories?
858        if (requestProperties != null) {
859          if ((requestProperties.toString()).equals("{prop.requester=MultiSpectral}")) {
860            return null;
861          }
862        }
863
864        GeoLocationInfo ginfo = null;
865        GeoSelection geoSelection = null;
866        
867        // TJJ 25 Sep 2014 found this case to be needed for Calypso data, need to init
868        // with default data selection arg passed in to avoid NPE.
869        if (dataChoice.getDataSelection() == null) {
870                dataChoice.setDataSelection(dataSelection);
871        }
872        
873        if ((dataSelection != null) && (dataSelection.getGeoSelection() != null)) {
874          geoSelection = (dataSelection.getGeoSelection().getBoundingBox() != null) ? dataSelection.getGeoSelection() :
875                                    dataChoice.getDataSelection().getGeoSelection();
876        }
877
878        if (geoSelection != null) {
879          ginfo = geoSelection.getBoundingBox();
880        }
881
882        Data data = null;
883        if (adapters == null) {
884          return data;
885        }
886
887        HashMap subset = null;
888        MultiDimensionSubset select = null;
889
890        Hashtable table = dataChoice.getProperties();
891        Enumeration keys = table.keys();
892        while (keys.hasMoreElements()) {
893           Object key = keys.nextElement();
894           if (key instanceof MultiDimensionSubset) {
895              select = (MultiDimensionSubset) table.get(key);
896           }
897        }
898
899
900        try {
901            subset = null;
902            if (ginfo != null) {
903              subset = adapter.getSubsetFromLonLatRect(ginfo.getMinLat(), ginfo.getMaxLat(),
904                                                       ginfo.getMinLon(), ginfo.getMaxLon(),
905                                                       geoSelection.getXStride(),
906                                                       geoSelection.getYStride(),
907                                                       geoSelection.getZStride());
908              if (subset == null && select != null) {
909                subset = select.getSubset();
910              }
911            }
912            else {
913              if (select != null) {
914                subset = select.getSubset();
915              }
916              
917              if (dataSelection != null) {
918                Hashtable props = dataSelection.getProperties();
919              }
920            }
921            
922            if (subset != null) {
923              data = adapter.getData(subset);
924              data = applyProperties(data, dataChoiceProps, subset);
925            }
926        } catch (Exception e) {
927            e.printStackTrace();
928            System.out.println("getData exception e=" + e);
929        }
930
931        return data;
932    }
933
934    protected Data applyProperties(Data data, Hashtable requestProperties, HashMap subset) 
935          throws VisADException, RemoteException {
936      Data new_data = data;
937
938      if (requestProperties == null) {
939        new_data = data;
940        return new_data;
941      }
942
943      if (requestProperties.containsKey("medianFilter")) {
944        String[] items = (String[]) requestProperties.get("medianFilter");
945        double window_lenx = Double.parseDouble(items[0]);
946        double window_leny = Double.parseDouble(items[1]);
947        GriddedSet domainSet = (GriddedSet) ((FlatField)data).getDomainSet();
948        int[] lens = domainSet.getLengths();
949        float[] range_values = (((FlatField)data).getFloats())[0];
950        range_values =
951           ProfileAlongTrack.medianFilter(range_values, lens[0], lens[1],
952                               (int)window_lenx, (int)window_leny);
953        ((FlatField)new_data).setSamples(new float[][] {range_values});
954      }
955      if (requestProperties.containsKey("setBelowSfcMissing")) {
956        FlatField track = (FlatField) track_adapter.getData(subset);
957        float[] sfcElev = (track.getFloats())[0];
958        FlatField field = (FlatField) new_data;
959        GriddedSet gset = (GriddedSet) field.getDomainSet();
960        float[][] samples = gset.getSamples(false);
961        int[] lens = gset.getLengths();
962        float[] range_values = (field.getFloats())[0];
963
964        int trkIdx = ((ProfileAlongTrack3D)adapters[0]).adapter2D.getTrackTupIdx();
965        int vrtIdx = ((ProfileAlongTrack3D)adapters[0]).adapter2D.getVertTupIdx();
966
967        int k = 0;
968        for (int j=0; j<lens[trkIdx]; j++) {
969          float val = sfcElev[j]*1000f; // convert to meters
970          for (int i=0; i<lens[vrtIdx]; i++) {
971            if (vrtIdx < trkIdx) k = i + j*lens[0];
972            if (trkIdx < vrtIdx) k = j + i*lens[0];
973            if (samples[2][k] <= val || samples[2][k] < 0.0) {
974              range_values[k] = Float.NaN;
975            }
976          }
977        }
978        field.setSamples(new float[][] {range_values});
979      }
980      return new_data;
981    }
982
983    protected void initDataSelectionComponents(
984         List<DataSelectionComponent> components,
985             final DataChoice dataChoice) {
986
987      if (hasImagePreview) {
988        try {
989          FlatField image = (FlatField) getDataInner(dataChoice, null, null, null);
990          components.add(new PreviewSelection(dataChoice, image, null));
991          //components.add(new edu.wisc.ssec.mcidasv.data.PreviewSelectionNew(dataChoice, image));
992        } catch (Exception e) {
993          System.out.println("Can't make PreviewSelection: "+e);
994          e.printStackTrace();
995        }
996      }
997      if (hasTrackPreview) {
998        try {
999          FlatField track = track_adapter.getData(track_adapter.getDefaultSubset());
1000          components.add(new TrackSelection(dataChoice, track));
1001        } catch (Exception e) {
1002          System.out.println("Can't make PreviewSelection: "+e);
1003          e.printStackTrace();
1004        }
1005      }
1006    }
1007}
1008
1009class TrackSelection extends DataSelectionComponent {
1010      DataChoice dataChoice;
1011      FlatField track;
1012
1013      double[] x_coords = new double[2];
1014      double[] y_coords = new double[2];
1015      boolean hasSubset = true;
1016      MapProjectionDisplayJ3D mapProjDsp;
1017      DisplayMaster dspMaster;
1018
1019      int trackStride;
1020      int verticalStride;
1021
1022      JTextField trkStr;
1023      JTextField vrtStr;
1024
1025
1026   TrackSelection(DataChoice dataChoice, FlatField track) throws VisADException, RemoteException {
1027        super("track");
1028        this.dataChoice = dataChoice;
1029        this.track = track;
1030        mapProjDsp = new MapProjectionDisplayJ3D(MapProjectionDisplay.MODE_2Din3D);
1031        mapProjDsp.enableRubberBanding(false);
1032        dspMaster = mapProjDsp;
1033        mapProjDsp.setMapProjection(getDataProjection());
1034        LineDrawing trackDsp = new LineDrawing("track");
1035        trackDsp.setLineWidth(2f);
1036        trackDsp.setData(track);
1037        mapProjDsp.addDisplayable(trackDsp);
1038
1039
1040        MapLines mapLines  = new MapLines("maplines");
1041        URL      mapSource =
1042        mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPU");
1043        try {
1044            BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
1045            mapLines.setMapLines(mapAdapter.getData());
1046            mapLines.setColor(java.awt.Color.cyan);
1047            mapProjDsp.addDisplayable(mapLines);
1048        } catch (Exception excp) {
1049            System.out.println("Can't open map file " + mapSource);
1050            System.out.println(excp);
1051        }
1052                                                                                                                                                     
1053        mapLines  = new MapLines("maplines");
1054        mapSource =
1055        mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPW");
1056        try {
1057            BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
1058            mapLines.setMapLines(mapAdapter.getData());
1059            mapLines.setColor(java.awt.Color.cyan);
1060            mapProjDsp.addDisplayable(mapLines);
1061        } catch (Exception excp) {
1062            System.out.println("Can't open map file " + mapSource);
1063            System.out.println(excp);
1064        }
1065                                                                                                                                                     
1066        mapLines  = new MapLines("maplines");
1067        mapSource =
1068        mapProjDsp.getClass().getResource("/auxdata/maps/OUTLHPOL");
1069        try {
1070            BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
1071            mapLines.setMapLines(mapAdapter.getData());
1072            mapLines.setColor(java.awt.Color.cyan);
1073            mapProjDsp.addDisplayable(mapLines);
1074        } catch (Exception excp) {
1075            System.out.println("Can't open map file " + mapSource);
1076            System.out.println(excp);
1077        }
1078
1079        final LineDrawing selectBox = new LineDrawing("select");
1080        selectBox.setColor(Color.green);
1081
1082        final RubberBandBox rbb =
1083            new RubberBandBox(RealType.Longitude, RealType.Latitude, 1);
1084        rbb.setColor(Color.green);
1085        rbb.addAction(new CellImpl() {
1086          public void doAction()
1087             throws VisADException, RemoteException
1088           {
1089              Gridded2DSet set = rbb.getBounds();
1090              float[] low = set.getLow();
1091              float[] hi = set.getHi();
1092              x_coords[0] = low[0];
1093              x_coords[1] = hi[0];
1094              y_coords[0] = low[1];
1095              y_coords[1] = hi[1];
1096              
1097              SampledSet[] sets = new SampledSet[4];
1098              sets[0] = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, new float[][] {{low[0], hi[0]}, {low[1], low[1]}}, 2);
1099              sets[1] = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, new float[][] {{hi[0], hi[0]}, {low[1], hi[1]}}, 2);
1100              sets[2] = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, new float[][] {{hi[0], low[0]}, {hi[1], hi[1]}}, 2);
1101              sets[3] = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, new float[][] {{low[0], low[0]}, {hi[1], low[1]}}, 2);
1102              UnionSet uset = new UnionSet(sets);
1103              selectBox.setData(uset);
1104           }
1105        });
1106        dspMaster.addDisplayable(rbb);
1107        dspMaster.addDisplayable(selectBox);
1108
1109        dspMaster.draw();
1110   }
1111
1112       public MapProjection getDataProjection() {
1113         MapProjection mp = null;
1114         try {
1115           mp = new ProjectionCoordinateSystem(new LatLonProjection());
1116         } catch (Exception e) {
1117             System.out.println(" getDataProjection"+e);
1118         }
1119         return mp;
1120       }
1121
1122      protected JComponent doMakeContents() {
1123        try {
1124          JPanel panel = new JPanel(new BorderLayout());
1125          panel.add("Center", dspMaster.getDisplayComponent());
1126
1127          JPanel stridePanel = new JPanel(new FlowLayout());
1128          trkStr = new JTextField(Integer.toString(5), 3);
1129          vrtStr = new JTextField(Integer.toString(2), 3);
1130          trkStr.addActionListener(new ActionListener() {
1131              public void actionPerformed(ActionEvent ae) {
1132                setTrackStride(Integer.valueOf(trkStr.getText().trim()));
1133              }
1134          });
1135          vrtStr.addActionListener(new ActionListener() {
1136              public void actionPerformed(ActionEvent ae) {
1137                setVerticalStride(Integer.valueOf(vrtStr.getText().trim()));
1138              }
1139          });
1140
1141          stridePanel.add(new JLabel("track stride: "));
1142          stridePanel.add(trkStr);
1143          stridePanel.add(new JLabel("vertical stride: "));
1144          stridePanel.add(vrtStr);
1145          panel.add("South", stridePanel);
1146
1147          return panel;
1148        }
1149        catch (Exception e) {
1150          System.out.println(e);
1151        }
1152        return null;
1153      }
1154                                                                                                                                                     
1155      public void setTrackStride(int stride) {
1156        trackStride = stride;
1157      }
1158
1159      public void setVerticalStride(int stride) {
1160        verticalStride = stride;
1161      }
1162
1163      public void setTrackStride() {
1164        trackStride = Integer.valueOf(trkStr.getText().trim());
1165      }
1166
1167      public void setVerticalStride() {
1168        verticalStride = Integer.valueOf(vrtStr.getText().trim());
1169      }
1170
1171      public void applyToDataSelection(DataSelection dataSelection) {
1172         setTrackStride();
1173         setVerticalStride();
1174         if (hasSubset) {
1175           GeoSelection geoSelect = new GeoSelection(
1176                new GeoLocationInfo(y_coords[1], x_coords[0], y_coords[0], x_coords[1]));
1177           geoSelect.setXStride(trackStride);
1178           geoSelect.setYStride(verticalStride);
1179           dataSelection.setGeoSelection(geoSelect);
1180         }
1181      }
1182}