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