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 */ 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 Hashtable table = dataChoice.getProperties(); 187 table.put(MultiDimensionSubset.key, subset); 188 189 190 track = (FlatField) dataSource.getData(dataChoice, null, getDataSelection(), dataSource.getProperties()); 191 192 LineDrawing trackDsp = new LineDrawing("track"); 193 trackDsp.setLineWidth(2f); 194 trackDsp.setData(track.getDomainSet()); 195 mainViewMaster.addDisplayable(trackDsp); 196 197 // ??? setConstantPosition(val, display real type) ?? 198 locOnTrack = new SelectorPoint("marker", new EarthLocationTuple(10, 10, 0)); 199// locOnTrack.setMarker(ShapeUtility.makeShape(ShapeUtility.CROSS)); 200 VisADGeometryArray[] markerShape = ShapeUtility.createShape(ShapeUtility.CROSS); 201 locOnTrack.setMarker(markerShape[0]); 202 mainViewMaster.addDisplayable(locOnTrack); 203 locOnTrack.setScale(0.1f); 204 205 trackDisplay = trackDsp; 206 return track; 207 } 208 209 private DisplayableData create3DDisplay(FlatField data) throws VisADException, RemoteException { 210 RealType imageRangeType = (RealType) ((FunctionType)data.getType()).getRange(); 211 HydraRGBDisplayable imageDsp = new HydraRGBDisplayable("image", imageRangeType, (RealType) null, true, null); 212 imageDsp.setDefaultRenderer(); 213 imageDsp.setData(data); 214 return imageDsp; 215 } 216 217 private void create3DMesh(FlatField track) throws VisADException, RemoteException { 218 float del_lat = 2f; 219 int n_sets = 3; 220 GriddedSet set = (GriddedSet) track.getDomainSet(); 221 222 float[][] samples = set.getSamples(); 223 float[][] samples3D = new float[][] {samples[0], samples[1], new float[samples[0].length]}; 224 225 SampledSet[] sets = new SampledSet[n_sets]; 226 Tuple[] labels = new Tuple[n_sets]; 227 float alt_start = 2000; 228 float alt_inc = 5000; 229 for (int k=0; k<n_sets; k++) { 230 for (int i=0; i<samples3D[2].length; i++) { 231 samples3D[2][i] = alt_start + k*alt_inc; 232 } 233 sets[k] = new Gridded3DSet(RealTupleType.SpatialEarth3DTuple, samples3D, samples3D[2].length); 234 Tuple tup = new Tuple(new TupleType(new MathType[] {RealTupleType.SpatialEarth3DTuple, TextType.Generic}), 235 new Data[] {new RealTuple(RealTupleType.SpatialEarth3DTuple, 236 new double[] {samples3D[0][0], samples3D[1][0] - del_lat, samples3D[2][0]}), 237 new Text(TextType.Generic, Float.toString(samples3D[2][0]))}); 238 labels[k] = tup; 239 } 240 241 UnionSet u_set = new UnionSet(sets); 242 LineDrawing meshDsp = new LineDrawing("mesh"); 243 meshDsp.setLineWidth(2f); 244 meshDsp.setData(u_set); 245 mainViewMaster.addDisplayable(meshDsp); 246 247 TextDisplayable txtDsp = new TextDisplayable(TextType.Generic); 248 txtDsp.setData(new Tuple(labels)); 249 txtDsp.setLineWidth(2f); 250 mainViewMaster.addDisplayable(txtDsp); 251 252 meshDisplay = meshDsp; 253 textDisplay = txtDsp; 254 255 return; 256 } 257 258 private XYDisplay makeDisplay2D(final FlatField data) throws VisADException, RemoteException { 259 260 FunctionType fncType = (FunctionType) data.getType(); 261 262 RealType domainType = RealType.Generic; 263 RealType rangeType = (RealType) fncType.getRange(); 264 265 final Set domainSet = data.getDomainSet(); 266 int len = domainSet.getLength(); 267 Integer1DSet newDomain = new Integer1DSet(len); 268 FlatField newFF = new FlatField(new FunctionType(RealType.Generic, rangeType), newDomain); 269 newFF.setSamples(data.getFloats()); 270 271 XYDisplay master = new XYDisplay("2D disp", domainType, rangeType); 272 273 master.showAxisScales(true); 274 master.setAspect(2.5, 0.75); 275 double[] proj = master.getProjectionMatrix(); 276 proj[0] = 0.35; 277 proj[5] = 0.35; 278 proj[10] = 0.35; 279 master.setProjectionMatrix(proj); 280 281 ScalarMap xmap = new ScalarMap(domainType, Display.XAxis); 282 ScalarMap ymap = new ScalarMap(rangeType, Display.YAxis); 283 ScalarMap txtMap = new ScalarMap(TextType.Generic, Display.Text); 284 285 LocalDisplay display = master.getDisplay(); 286 display.addMap(xmap); 287 display.addMap(ymap); 288 display.addMap(txtMap); 289 290 DataReference dataRef = new DataReferenceImpl("data"); 291 dataRef.setData(newFF); 292 display.addReference(dataRef); 293 294 final DataReference txtRef = new DataReferenceImpl("text"); 295 display.addReference(txtRef, new ConstantMap[] {new ConstantMap(0.9, Display.YAxis)}); 296 297 298 class MyDragLine extends DragLine { 299 public MyDragLine(Gridded1DSet domain, RealType domainType, RealType rangeType, 300 final float lastSelectedValue, LocalDisplay display, final String controlId, 301 final ConstantMap[] color, float[] YRANGE) throws Exception { 302 super(domain, domainType, rangeType, lastSelectedValue, display, controlId, color, YRANGE); 303 } 304 305 public void update() { 306 int idx = (new Float(this.lastSelectedValue)).intValue(); 307 try { 308 float[][] val = domainSet.indexToValue(new int[] {idx}); 309 locOnTrack.setPoint(new EarthLocationTuple(val[1][0], val[0][0], 0)); 310 float rangeVal = (float) ((Real)data.getSample(idx)).getValue(); 311 Tuple tup = new Tuple(new Data[] {new Real(RealType.Generic, (double) idx), new Text(TextType.Generic, numFmt.format(rangeVal))}); 312 txtRef.setData(tup); 313 314 } catch (Exception e) { 315 System.out.println(e); 316 } 317 } 318 } 319 320 try { 321 MyDragLine draggable = new MyDragLine(newDomain, domainType, rangeType, 100f, display, 322 "dragLine", MultiSpectralDisplay.makeColorMap(Color.GREEN), new float[] {0, 16}); 323 } catch (Exception e) { 324 e.printStackTrace(); 325 } 326 327 return master; 328 } 329 330 protected ColorTable getInitialColorTable() { 331 return getDisplayConventions().getParamColorTable(imageRangeType.getName()); 332 } 333 334 protected Range getInitialRange() throws RemoteException, VisADException { 335 Range range = getDisplayConventions().getParamRange(imageRangeType.getName(), null); 336 if (range != null) { 337 setSelectRange(range); 338 return range; 339 } 340 else { 341 return super.getInitialRange(); 342 } 343 } 344 345 public void doRemove() throws RemoteException, VisADException{ 346 347 if (meshDisplay != null) mainViewMaster.removeDisplayable(meshDisplay); 348 if (textDisplay != null) mainViewMaster.removeDisplayable(textDisplay); 349 if (trackDisplay != null) mainViewMaster.removeDisplayable(trackDisplay); 350 super.doRemove(); 351 } 352 353 public void setDisplayVisibility(boolean on) { 354 super.setDisplayVisibility(on); 355 try { 356 if (meshDisplay != null) meshDisplay.setVisible(on); 357 if (textDisplay != null) textDisplay.setVisible(on); 358 if (trackDisplay != null) trackDisplay.setVisible(on); 359 } 360 catch( Exception e) { 361 e.printStackTrace(); 362 } 363 } 364 365 public Container doMakeContents() { 366 try { 367 JTabbedPane pane = new JTabbedPane(); 368 if (display2D != null) { 369 pane.add("Display", GuiUtils.inset(display2D.getDisplayComponent(), 5)); 370 } 371 pane.add("Settings", 372 GuiUtils.inset(GuiUtils.top(doMakeWidgetComponent()), 5)); 373 GuiUtils.handleHeavyWeightComponentsInTabs(pane); 374 return pane; 375 } catch (Exception e) { 376 logException("MultiSpectralControl.doMakeContents", e); 377 } 378 return null; 379 } 380 381 protected JComponent doMakeWidgetComponent() { 382 List<Component> widgetComponents; 383 try { 384 List<ControlWidget> controlWidgets = new ArrayList<ControlWidget>(); 385 getControlWidgets(controlWidgets); 386 widgetComponents = ControlWidget.fillList(controlWidgets); 387 } catch (Exception e) { 388 LogUtil.logException("Problem building the ProfileAlongTrackControl settings", e); 389 widgetComponents = new ArrayList<Component>(); 390 widgetComponents.add(new JLabel("Error building component...")); 391 } 392 393 GuiUtils.tmpInsets = new Insets(4, 8, 4, 8); 394 GuiUtils.tmpFill = GridBagConstraints.HORIZONTAL; 395 return GuiUtils.doLayout(widgetComponents, 2, GuiUtils.WT_NY, GuiUtils.WT_N); 396 } 397 398}