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