001 /* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2013 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 029 package edu.wisc.ssec.mcidasv.control; 030 031 import java.awt.Container; 032 import java.awt.Component; 033 import java.awt.Insets; 034 import java.awt.Color; 035 import java.awt.GridBagConstraints; 036 import javax.swing.JLabel; 037 import javax.swing.JComponent; 038 import javax.swing.JTabbedPane; 039 import java.rmi.RemoteException; 040 import java.util.Enumeration; 041 import java.util.HashMap; 042 import java.util.Hashtable; 043 import java.util.List; 044 import java.util.ArrayList; 045 import java.text.DecimalFormat; 046 047 import visad.Data; 048 import visad.DataReference; 049 import visad.DataReferenceImpl; 050 import visad.FlatField; 051 import visad.Real; 052 import visad.FunctionType; 053 import visad.Integer1DSet; 054 import visad.GriddedSet; 055 import visad.Gridded1DSet; 056 import visad.Gridded3DSet; 057 import visad.MathType; 058 import visad.RealTuple; 059 import visad.RealTupleType; 060 import visad.RealType; 061 import visad.Set; 062 import visad.SampledSet; 063 import visad.SimpleSet; 064 import visad.Text; 065 import visad.TextType; 066 import visad.Tuple; 067 import visad.TupleType; 068 import visad.UnionSet; 069 import visad.ScalarMap; 070 import visad.Display; 071 import visad.LocalDisplay; 072 import visad.ConstantMap; 073 import visad.VisADException; 074 import visad.VisADGeometryArray; 075 import visad.georef.LatLonTuple; 076 import visad.georef.EarthLocationTuple; 077 import visad.util.Util; 078 079 import ucar.unidata.idv.control.ControlWidget; 080 import ucar.unidata.data.DataChoice; 081 import ucar.unidata.data.DirectDataChoice; 082 import ucar.unidata.data.DerivedDataChoice; 083 import ucar.unidata.data.GeoSelection; 084 import ucar.unidata.data.GeoSelectionPanel; 085 import ucar.unidata.idv.IntegratedDataViewer; 086 import ucar.unidata.idv.ViewManager; 087 import ucar.unidata.idv.control.DisplayControlImpl; 088 import ucar.unidata.util.ColorTable; 089 import ucar.unidata.util.GuiUtils; 090 import ucar.unidata.util.LogUtil; 091 import ucar.unidata.util.Range; 092 import ucar.visad.display.DisplayMaster; 093 import ucar.visad.display.DisplayableData; 094 import ucar.visad.display.LineDrawing; 095 import ucar.visad.display.TextDisplayable; 096 import ucar.visad.display.XYDisplay; 097 import ucar.visad.display.SelectorPoint; 098 import ucar.visad.ShapeUtility; 099 100 import edu.wisc.ssec.mcidasv.data.hydra.HydraRGBDisplayable; 101 import edu.wisc.ssec.mcidasv.data.hydra.MultiDimensionDataSource; 102 import edu.wisc.ssec.mcidasv.data.hydra.MultiDimensionSubset; 103 import edu.wisc.ssec.mcidasv.data.hydra.GrabLineRendererJ3D; 104 import edu.wisc.ssec.mcidasv.display.hydra.DragLine; 105 import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay; 106 107 108 109 public class ProfileAlongTrackControl extends DisplayControlImpl { 110 111 private DataChoice dataChoice; 112 113 private DisplayableData imageDisplay; 114 private DisplayableData trackDisplay; 115 private DisplayableData meshDisplay; 116 private DisplayableData textDisplay; 117 118 private DisplayMaster mainViewMaster; 119 120 private RealType imageRangeType; 121 122 public MultiDimensionSubset subset; 123 124 private MultiDimensionDataSource dataSource; 125 126 private FlatField track; 127 128 private GeoSelection geoSelection; 129 130 private GeoSelectionPanel geoSelectionPanel; 131 132 private XYDisplay display2D = null; 133 134 private SelectorPoint locOnTrack; 135 136 private DecimalFormat numFmt = new DecimalFormat(); 137 138 139 public ProfileAlongTrackControl() { 140 super(); 141 setAttributeFlags(FLAG_COLORTABLE | FLAG_SELECTRANGE); 142 } 143 144 public boolean init(DataChoice dataChoice) throws VisADException, RemoteException { 145 this.dataChoice = dataChoice; 146 FlatField data; 147 148 if (dataChoice instanceof DerivedDataChoice) { 149 data = (FlatField) dataChoice.getData(getDataSelection()); 150 } 151 else { 152 dataSource = (MultiDimensionDataSource) ((DirectDataChoice)dataChoice).getDataSource(); 153 ViewManager vm = getViewManager(); 154 mainViewMaster = vm.getMaster(); 155 156 Hashtable table = dataChoice.getProperties(); 157 Enumeration keys = table.keys(); 158 while (keys.hasMoreElements()) { 159 Object key = keys.nextElement(); 160 if (key instanceof MultiDimensionSubset) { 161 subset = (MultiDimensionSubset) table.get(key); 162 } 163 } 164 subset.setGeoSelection(getDataSelection().getGeoSelection()); 165 166 data = (FlatField) dataSource.getData(dataChoice, null, getDataSelection(), dataSource.getProperties()); 167 } 168 169 if (data == null) { 170 return false; 171 } 172 173 imageRangeType = (RealType) ((FunctionType)data.getType()).getRange(); 174 track = createTrackDisplay(dataChoice); 175 imageDisplay = create3DDisplay(data); 176 addDisplayable(imageDisplay, FLAG_COLORTABLE | FLAG_SELECTRANGE); 177 if (track != null) create3DMesh(track); 178 179 // 2D Display in Control Window, only line graph type display for now 180 if (((SimpleSet)data.getDomainSet()).getManifoldDimension() == 1) { 181 display2D = makeDisplay2D(data); 182 } 183 184 return true; 185 } 186 187 public synchronized void dataChanged() { 188 super.dataChanged(); 189 } 190 191 private FlatField createTrackDisplay(DataChoice dataChoice) throws VisADException, RemoteException { 192 IntegratedDataViewer idv = getIdv(); 193 FlatField track = null; 194 195 dataChoice = dataSource.findDataChoice("Track3D"); 196 if (dataChoice == null) { 197 return null; 198 } 199 200 track = (FlatField) dataSource.getData(dataSource.findDataChoice("Track3D"), null, getDataSelection(), dataSource.getProperties()); 201 202 LineDrawing trackDsp = new LineDrawing("track"); 203 trackDsp.setLineWidth(2f); 204 trackDsp.setData(track.getDomainSet()); 205 mainViewMaster.addDisplayable(trackDsp); 206 207 // ??? setConstantPosition(val, display real type) ?? 208 locOnTrack = new SelectorPoint("marker", new EarthLocationTuple(10, 10, 0)); 209 // locOnTrack.setMarker(ShapeUtility.makeShape(ShapeUtility.CROSS)); 210 VisADGeometryArray[] markerShape = ShapeUtility.createShape(ShapeUtility.CROSS); 211 locOnTrack.setMarker(markerShape[0]); 212 mainViewMaster.addDisplayable(locOnTrack); 213 locOnTrack.setScale(0.1f); 214 215 trackDisplay = trackDsp; 216 return track; 217 } 218 219 private DisplayableData create3DDisplay(FlatField data) throws VisADException, RemoteException { 220 RealType imageRangeType = (RealType) ((FunctionType)data.getType()).getRange(); 221 HydraRGBDisplayable imageDsp = new HydraRGBDisplayable("image", imageRangeType, (RealType) null, true, null); 222 imageDsp.setDefaultRenderer(); 223 imageDsp.setData(data); 224 return imageDsp; 225 } 226 227 private void create3DMesh(FlatField track) throws VisADException, RemoteException { 228 float del_lat = 2f; 229 int n_sets = 3; 230 GriddedSet set = (GriddedSet) track.getDomainSet(); 231 232 float[][] samples = set.getSamples(); 233 float[][] samples3D = new float[][] {samples[0], samples[1], new float[samples[0].length]}; 234 235 SampledSet[] sets = new SampledSet[n_sets]; 236 Tuple[] labels = new Tuple[n_sets]; 237 float alt_start = 2000; 238 float alt_inc = 5000; 239 for (int k=0; k<n_sets; k++) { 240 for (int i=0; i<samples3D[2].length; i++) { 241 samples3D[2][i] = alt_start + k*alt_inc; 242 } 243 sets[k] = new Gridded3DSet(RealTupleType.SpatialEarth3DTuple, samples3D, samples3D[2].length); 244 Tuple tup = new Tuple(new TupleType(new MathType[] {RealTupleType.SpatialEarth3DTuple, TextType.Generic}), 245 new Data[] {new RealTuple(RealTupleType.SpatialEarth3DTuple, 246 new double[] {samples3D[0][0], samples3D[1][0] - del_lat, samples3D[2][0]}), 247 new Text(TextType.Generic, Float.toString(samples3D[2][0]))}); 248 labels[k] = tup; 249 } 250 251 UnionSet u_set = new UnionSet(sets); 252 LineDrawing meshDsp = new LineDrawing("mesh"); 253 meshDsp.setLineWidth(2f); 254 meshDsp.setData(u_set); 255 mainViewMaster.addDisplayable(meshDsp); 256 257 TextDisplayable txtDsp = new TextDisplayable(TextType.Generic); 258 txtDsp.setData(new Tuple(labels)); 259 txtDsp.setLineWidth(2f); 260 mainViewMaster.addDisplayable(txtDsp); 261 262 meshDisplay = meshDsp; 263 textDisplay = txtDsp; 264 265 return; 266 } 267 268 private XYDisplay makeDisplay2D(final FlatField data) throws VisADException, RemoteException { 269 270 FunctionType fncType = (FunctionType) data.getType(); 271 272 RealType domainType = RealType.Generic; 273 RealType rangeType = (RealType) fncType.getRange(); 274 275 final Set domainSet = data.getDomainSet(); 276 int len = domainSet.getLength(); 277 Integer1DSet newDomain = new Integer1DSet(len); 278 FlatField newFF = new FlatField(new FunctionType(RealType.Generic, rangeType), newDomain); 279 newFF.setSamples(data.getFloats()); 280 281 XYDisplay master = new XYDisplay("2D disp", domainType, rangeType); 282 283 master.showAxisScales(true); 284 master.setAspect(2.5, 0.75); 285 double[] proj = master.getProjectionMatrix(); 286 proj[0] = 0.35; 287 proj[5] = 0.35; 288 proj[10] = 0.35; 289 master.setProjectionMatrix(proj); 290 291 ScalarMap xmap = new ScalarMap(domainType, Display.XAxis); 292 ScalarMap ymap = new ScalarMap(rangeType, Display.YAxis); 293 ScalarMap txtMap = new ScalarMap(TextType.Generic, Display.Text); 294 295 LocalDisplay display = master.getDisplay(); 296 display.addMap(xmap); 297 display.addMap(ymap); 298 display.addMap(txtMap); 299 300 DataReference dataRef = new DataReferenceImpl("data"); 301 dataRef.setData(newFF); 302 display.addReference(dataRef); 303 304 final DataReference txtRef = new DataReferenceImpl("text"); 305 display.addReference(txtRef, new ConstantMap[] {new ConstantMap(0.9, Display.YAxis)}); 306 307 308 class MyDragLine extends DragLine { 309 public MyDragLine(Gridded1DSet domain, RealType domainType, RealType rangeType, 310 final float lastSelectedValue, LocalDisplay display, final String controlId, 311 final ConstantMap[] color, float[] YRANGE) throws Exception { 312 super(domain, domainType, rangeType, lastSelectedValue, display, controlId, color, YRANGE); 313 } 314 315 public void update() { 316 int idx = (new Float(this.lastSelectedValue)).intValue(); 317 try { 318 float[][] val = domainSet.indexToValue(new int[] {idx}); 319 locOnTrack.setPoint(new EarthLocationTuple(val[1][0], val[0][0], 0)); 320 float rangeVal = (float) ((Real)data.getSample(idx)).getValue(); 321 Tuple tup = new Tuple(new Data[] {new Real(RealType.Generic, (double) idx), new Text(TextType.Generic, numFmt.format(rangeVal))}); 322 txtRef.setData(tup); 323 324 } catch (Exception e) { 325 System.out.println(e); 326 } 327 } 328 } 329 330 try { 331 MyDragLine draggable = new MyDragLine(newDomain, domainType, rangeType, 100f, display, 332 "dragLine", MultiSpectralDisplay.makeColorMap(Color.GREEN), new float[] {0, 16}); 333 } catch (Exception e) { 334 e.printStackTrace(); 335 } 336 337 return master; 338 } 339 340 protected ColorTable getInitialColorTable() { 341 return getDisplayConventions().getParamColorTable(imageRangeType.getName()); 342 } 343 344 protected Range getInitialRange() throws RemoteException, VisADException { 345 Range range = getDisplayConventions().getParamRange(imageRangeType.getName(), null); 346 if (range != null) { 347 setSelectRange(range); 348 return range; 349 } 350 else { 351 return super.getInitialRange(); 352 } 353 } 354 355 public void doRemove() throws RemoteException, VisADException{ 356 357 if (meshDisplay != null) mainViewMaster.removeDisplayable(meshDisplay); 358 if (textDisplay != null) mainViewMaster.removeDisplayable(textDisplay); 359 if (trackDisplay != null) mainViewMaster.removeDisplayable(trackDisplay); 360 super.doRemove(); 361 } 362 363 public void setDisplayVisibility(boolean on) { 364 super.setDisplayVisibility(on); 365 try { 366 if (meshDisplay != null) meshDisplay.setVisible(on); 367 if (textDisplay != null) textDisplay.setVisible(on); 368 if (trackDisplay != null) trackDisplay.setVisible(on); 369 } 370 catch( Exception e) { 371 e.printStackTrace(); 372 } 373 } 374 375 public Container doMakeContents() { 376 try { 377 JTabbedPane pane = new JTabbedPane(); 378 if (display2D != null) { 379 pane.add("Display", GuiUtils.inset(display2D.getDisplayComponent(), 5)); 380 } 381 pane.add("Settings", 382 GuiUtils.inset(GuiUtils.top(doMakeWidgetComponent()), 5)); 383 GuiUtils.handleHeavyWeightComponentsInTabs(pane); 384 return pane; 385 } catch (Exception e) { 386 logException("MultiSpectralControl.doMakeContents", e); 387 } 388 return null; 389 } 390 391 protected JComponent doMakeWidgetComponent() { 392 List<Component> widgetComponents; 393 try { 394 List<ControlWidget> controlWidgets = new ArrayList<ControlWidget>(); 395 getControlWidgets(controlWidgets); 396 widgetComponents = ControlWidget.fillList(controlWidgets); 397 } catch (Exception e) { 398 LogUtil.logException("Problem building the ProfileAlongTrackControl settings", e); 399 widgetComponents = new ArrayList<Component>(); 400 widgetComponents.add(new JLabel("Error building component...")); 401 } 402 403 GuiUtils.tmpInsets = new Insets(4, 8, 4, 8); 404 GuiUtils.tmpFill = GridBagConstraints.HORIZONTAL; 405 return GuiUtils.doLayout(widgetComponents, 2, GuiUtils.WT_NY, GuiUtils.WT_N); 406 } 407 408 private JComponent getDisplayTab() { 409 return null; 410 } 411 }