001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2017
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 */
028package edu.wisc.ssec.mcidasv.data.hydra;
029
030import java.awt.BorderLayout;
031import java.awt.Color;
032import java.awt.FlowLayout;
033import java.awt.GridLayout;
034import java.awt.event.ActionEvent;
035import javax.swing.event.ChangeEvent;
036import java.awt.event.ActionListener;
037import javax.swing.event.ChangeListener;
038import java.net.URL;
039import java.rmi.RemoteException;
040import java.util.Map;
041import java.util.HashMap;
042import java.util.Hashtable;
043
044import javax.swing.JComponent;
045import javax.swing.JLabel;
046import javax.swing.JPanel;
047import javax.swing.JTextField;
048import javax.swing.JSlider;
049import javax.swing.DefaultBoundedRangeModel;
050
051import org.slf4j.Logger;
052import org.slf4j.LoggerFactory;
053
054import ucar.unidata.data.DataChoice;
055import ucar.unidata.data.DataSelection;
056import ucar.unidata.data.DataSelectionComponent;
057import ucar.unidata.data.GeoLocationInfo;
058import ucar.unidata.data.GeoSelection;
059import ucar.unidata.geoloc.projection.LatLonProjection;
060import ucar.unidata.view.geoloc.MapProjectionDisplay;
061import ucar.unidata.view.geoloc.MapProjectionDisplayJ3D;
062import ucar.unidata.view.geoloc.MapProjectionDisplayJ2D;
063import ucar.unidata.geoloc.ProjectionRect;
064import ucar.visad.ProjectionCoordinateSystem;
065import ucar.visad.display.DisplayMaster;
066import ucar.visad.display.LineDrawing;
067import ucar.visad.display.MapLines;
068import ucar.visad.display.RubberBandBox;
069import visad.CellImpl;
070import visad.FlatField;
071import visad.Gridded2DSet;
072import visad.RealTupleType;
073import visad.RealType;
074import visad.SampledSet;
075import visad.UnionSet;
076import visad.VisADException;
077import visad.data.mcidas.BaseMapAdapter;
078import visad.georef.MapProjection;
079import visad.GriddedSet;
080
081public class TrackSelection extends DataSelectionComponent {
082
083        private static final Logger logger = LoggerFactory.getLogger(TrackSelection.class);
084        
085        public static final int DEFAULT_TRACK_STRIDE = 5;
086        public static final int DEFAULT_VERTICAL_STRIDE = 2;
087        
088        DataChoice dataChoice;
089        FlatField track;
090
091        double[] x_coords = new double[2];
092        double[] y_coords = new double[2];
093        MapProjectionDisplayJ2D mapProjDsp;
094        DisplayMaster dspMaster;
095
096        int trackStride;
097        int verticalStride;
098
099        JTextField trkStr;
100        JTextField vrtStr;
101        JTextField widthFld;
102
103        LineDrawing trackSelectDsp;
104        float[][] trackLocs;
105        int trackLen;
106        int trackPos;
107        int trackStart;
108        int trackStop;
109        double trackWidthPercent = 5;
110        int selectWidth;
111        Map defaultSubset;
112
113        TrackSelection(DataChoice dataChoice, FlatField track, Map defaultSubset) throws VisADException, RemoteException {
114                super("track");
115                this.dataChoice = dataChoice;
116                this.track = track;
117                this.defaultSubset = defaultSubset;
118
119                GriddedSet gset = (GriddedSet)track.getDomainSet();
120                float[] lo = gset.getLow();
121                float[] hi = gset.getHi();
122                float[][] values = gset.getSamples();
123                
124                trackLen = values[0].length;
125                selectWidth = (int) (trackLen*(trackWidthPercent/100));
126                selectWidth /= 2;
127                trackPos = trackLen/2;
128                trackStart = trackPos - selectWidth;
129                trackStop = trackPos + selectWidth;
130                
131                trackLocs = values;
132                Gridded2DSet track2D = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple, new float[][] {values[0], values[1]}, values[0].length);
133                //mapProjDsp = new MapProjectionDisplayJ3D(MapProjectionDisplay.MODE_2Din3D);
134                mapProjDsp = new MapProjectionDisplayJ2D();
135                //mapProjDsp.enableRubberBanding(false);
136                dspMaster = mapProjDsp;
137                mapProjDsp.setMapProjection(getDataProjection(new ProjectionRect(lo[0],lo[1],hi[0],hi[1])));
138                LineDrawing trackDsp = new LineDrawing("track");
139                trackDsp.setLineWidth(0.5f);
140                trackDsp.setData(track2D);
141                
142                trackSelectDsp = new LineDrawing("trackSelect");
143                trackSelectDsp.setLineWidth(3f);
144                trackSelectDsp.setColor(java.awt.Color.green);
145                
146                updateTrackSelect();
147                
148                mapProjDsp.addDisplayable(trackDsp);
149                mapProjDsp.addDisplayable(trackSelectDsp);
150
151                MapLines mapLines = new MapLines("maplines");
152                URL mapSource = mapProjDsp.getClass().getResource(
153                                "/auxdata/maps/OUTLSUPU");
154                try {
155                        BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
156                        mapLines.setMapLines(mapAdapter.getData());
157                        mapLines.setColor(java.awt.Color.cyan);
158                        //mapProjDsp.addDisplayable(mapLines);
159                } catch (Exception excp) {
160                        logger.error("cannot open map file: " + mapSource, excp);
161                }
162
163                mapLines = new MapLines("maplines");
164                mapSource = mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPW");
165                try {
166                        BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
167                        mapLines.setMapLines(mapAdapter.getData());
168                        mapLines.setColor(java.awt.Color.cyan);
169                        mapProjDsp.addDisplayable(mapLines);
170                } catch (Exception excp) {
171                        logger.error("cannot open map file: " + mapSource, excp);
172                }
173
174                mapLines = new MapLines("maplines");
175                mapSource = mapProjDsp.getClass().getResource("/auxdata/maps/OUTLHPOL");
176                try {
177                        BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
178                        mapLines.setMapLines(mapAdapter.getData());
179                        mapLines.setColor(java.awt.Color.cyan);
180                        //mapProjDsp.addDisplayable(mapLines);
181                } catch (Exception excp) {
182                        logger.error("cannot open map file: " + mapSource, excp);
183                }
184
185                dspMaster.draw();
186        }
187
188        public MapProjection getDataProjection(ProjectionRect rect) {
189                MapProjection mp = null;
190                try {
191                        mp = new ProjectionCoordinateSystem(new LatLonProjection("blah", rect));
192                } catch (Exception e) {
193                        logger.error("error getting data projection", e);
194                }
195                return mp;
196        }
197
198        protected JComponent doMakeContents() {
199                try {
200                        JPanel panel = new JPanel(new BorderLayout());
201                        panel.add("Center", dspMaster.getDisplayComponent());
202
203                        JPanel stridePanel = new JPanel(new FlowLayout());
204                        trkStr = new JTextField(Integer.toString(TrackSelection.DEFAULT_TRACK_STRIDE), 3);
205                        vrtStr = new JTextField(Integer.toString(TrackSelection.DEFAULT_VERTICAL_STRIDE), 3);
206                        widthFld = new JTextField(Double.toString(trackWidthPercent), 3);
207                        
208                        trkStr.addActionListener(new ActionListener() {
209                                public void actionPerformed(ActionEvent ae) {
210                                        setTrackStride(Integer.valueOf(trkStr.getText().trim()));
211                                }
212                        });
213                        vrtStr.addActionListener(new ActionListener() {
214                                public void actionPerformed(ActionEvent ae) {
215                                        setVerticalStride(Integer.valueOf(vrtStr.getText().trim()));
216                                }
217                        });
218                        widthFld.addActionListener(new ActionListener() {
219                                public void actionPerformed(ActionEvent ae) {
220                                        setWidthPercent(Double.valueOf(widthFld.getText().trim()));
221                                }
222                        });
223
224                        stridePanel.add(new JLabel("Track Stride: "));
225                        stridePanel.add(trkStr);
226                        stridePanel.add(new JLabel("Vertical Stride: "));
227                        stridePanel.add(vrtStr);
228                        stridePanel.add(new JLabel("Width%: "));
229                        stridePanel.add(widthFld);
230
231                        JPanel selectPanel = new JPanel(new GridLayout(2,0));
232                        DefaultBoundedRangeModel brm = new DefaultBoundedRangeModel(trackStart, 0, 0, trackLen); 
233                        JSlider trackSelect = new JSlider(brm);
234                        trackSelect.addChangeListener( new ChangeListener() {
235                           public void stateChanged(ChangeEvent e) {
236                              trackPos = (int) ((JSlider)e.getSource()).getValue();
237                              updateTrackSelect();
238                           }
239                        }
240                        );
241                        selectPanel.add(trackSelect);
242                        selectPanel.add(stridePanel);
243                        panel.add("South", selectPanel);
244
245                        return panel;
246                } catch (Exception e) {
247                        logger.error("error creating contents", e);
248                }
249                return null;
250        }
251
252        public void setTrackStride(int stride) {
253                trackStride = stride;
254        }
255
256        public void setVerticalStride(int stride) {
257                verticalStride = stride;
258        }
259        
260        public void setWidthPercent(double percent) {
261                trackWidthPercent = percent;
262                selectWidth = (int) (trackLen*(trackWidthPercent/100));
263                selectWidth /= 2;
264                updateTrackSelect();
265        }
266
267        /**
268         * Update Track Stride if input text box holds a positive integer.
269         * 
270         * @return true if trackStride was updated
271         */
272        
273        public boolean setTrackStride() {
274                boolean setOk = false;
275                try {
276                        int newStride = Integer.valueOf(trkStr.getText().trim());
277                        if (newStride >= 1) {
278                           trackStride = newStride;
279                           setOk = true;
280                        }
281                        else {
282                           setOk = false;
283                        }
284                } catch (NumberFormatException nfe) {
285                        // do nothing, will return correct result code
286                }
287                return setOk;
288        }
289
290        /**
291         * Update Vertical Stride if input text box holds a positive integer.
292         * 
293         * @return true if verticalStride was updated
294         */
295        
296        public boolean setVerticalStride() {
297                boolean setOk = false;
298                try {
299                        int newStride = Integer.valueOf(vrtStr.getText().trim());
300                        if (newStride >= 1) {
301                           verticalStride = newStride;
302                           setOk = true;
303                        }
304                        else {
305                           setOk = false;
306                        }
307                } catch (NumberFormatException nfe) {
308                        // do nothing, will return correct result code
309                }
310                return setOk;
311        }
312
313        /**
314         * Update Vertical Stride if input text box holds a positive integer.
315         * 
316         * @return true if verticalStride was updated
317         */
318        
319        public boolean setWidthPercent() {
320                boolean setOk = false;
321                try {
322                        double newWidth = Double.valueOf(widthFld.getText().trim());
323                        trackWidthPercent = newWidth;
324                        setOk = true;
325                } catch (NumberFormatException nfe) {
326                        // do nothing, will return correct result code
327                }
328                return setOk;
329        }
330        
331        void updateTrackSelect() {
332               trackStart = trackPos - selectWidth;
333               if (trackStart < 0) trackStart = 0;
334               
335               trackStop = trackPos + selectWidth;
336               if (trackStop >= trackLen) trackStop = trackLen - 1;
337               
338               try {
339                  Gridded2DSet trck = new Gridded2DSet(RealTupleType.SpatialEarth2DTuple,
340                         new float[][] {java.util.Arrays.copyOfRange(trackLocs[0], trackStart, trackStop), 
341                                        java.util.Arrays.copyOfRange(trackLocs[1], trackStart, trackStop)}, 
342                               (trackStop - trackStart));
343                  trackSelectDsp.setData(trck);
344               }
345               catch (Exception exc) {
346                  exc.printStackTrace();
347               }           
348        }
349        
350        public void applyToDataSelection(DataSelection dataSelection) {
351                setTrackStride();
352                setVerticalStride();
353                setWidthPercent();
354
355                HashMap subset = (HashMap) ((HashMap)defaultSubset).clone();
356                double[] coords = (double[]) subset.get(ProfileAlongTrack.vertDim_name);
357
358                subset.put(ProfileAlongTrack.trackDim_name, new double[] {trackStart, trackStop, trackStride});
359                subset.put(ProfileAlongTrack.vertDim_name, new double[] {coords[0], coords[1], verticalStride});
360                  
361 
362                MultiDimensionSubset select = new MultiDimensionSubset(subset);
363
364                Hashtable table = dataChoice.getProperties();
365                table.put(MultiDimensionSubset.key, select);
366
367                table = dataSelection.getProperties();
368                table.put(MultiDimensionSubset.key, select);
369
370                dataChoice.setDataSelection(dataSelection);
371
372        }
373}