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