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 }