001 /*
002 * $Id: ScatterDisplay.java,v 1.61 2012/04/10 19:34:07 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
032 package edu.wisc.ssec.mcidasv.control;
033
034 import java.awt.BorderLayout;
035 import java.awt.Color;
036 import java.awt.Component;
037 import java.awt.Container;
038 import java.awt.Dimension;
039 import java.awt.FlowLayout;
040 import java.awt.GridLayout;
041 import java.awt.event.ActionEvent;
042 import java.awt.event.ActionListener;
043 import java.awt.event.WindowEvent;
044 import java.awt.event.WindowAdapter;
045 import java.awt.geom.Rectangle2D;
046 import java.net.URL;
047 import java.rmi.RemoteException;
048 import java.util.ArrayList;
049 import java.util.List;
050 import java.io.PrintWriter;
051 import java.io.File;
052
053 import javax.swing.JFrame;
054 import javax.swing.ButtonGroup;
055 import javax.swing.ImageIcon;
056 import javax.swing.JComponent;
057 import javax.swing.JPanel;
058 import javax.swing.JRadioButton;
059 import javax.swing.JToggleButton;
060 import javax.swing.JButton;
061 import javax.swing.JScrollPane;
062 import javax.swing.JTable;
063 import javax.swing.JFileChooser;
064 import javax.swing.filechooser.FileFilter;
065 import javax.swing.filechooser.FileNameExtensionFilter;
066 import javax.swing.table.AbstractTableModel;
067 import javax.swing.table.TableCellRenderer;
068 import javax.swing.border.CompoundBorder;
069 import javax.swing.border.EmptyBorder;
070 import javax.swing.border.LineBorder;
071
072 import org.slf4j.Logger;
073 import org.slf4j.LoggerFactory;
074
075 import visad.AxisScale;
076 import visad.BaseColorControl;
077 import visad.CellImpl;
078 import visad.CoordinateSystem;
079 import visad.Data;
080 import visad.DelaunayCustom;
081 import visad.DisplayEvent;
082 import visad.DisplayListener;
083 import visad.Real;
084 import visad.FieldImpl;
085 import visad.FlatField;
086 import visad.FunctionType;
087 import visad.Gridded2DSet;
088 import visad.Gridded3DSet;
089 import visad.Integer1DSet;
090 import visad.Linear2DSet;
091 import visad.LinearLatLonSet;
092 import visad.RealTupleType;
093 import visad.MathType;
094 import visad.RealType;
095 import visad.SampledSet;
096 import visad.ScalarMap;
097 import visad.Set;
098 import visad.SetType;
099 import visad.UnionSet;
100 import visad.VisADException;
101 import visad.data.mcidas.BaseMapAdapter;
102 import visad.georef.MapProjection;
103 import visad.georef.TrivialMapProjection;
104 import visad.python.JPythonMethods;
105
106 import ucar.unidata.data.DataAlias;
107 import ucar.unidata.data.DataChoice;
108 import ucar.unidata.data.DataSelection;
109 import ucar.unidata.data.grid.GridUtil;
110 import ucar.unidata.idv.DisplayConventions;
111 import ucar.unidata.idv.control.ColorTableWidget;
112 import ucar.unidata.idv.control.DisplayControlImpl;
113 import ucar.unidata.ui.colortable.ColorTableManager;
114 import ucar.unidata.util.ColorTable;
115 import ucar.unidata.util.LogUtil;
116 import ucar.unidata.util.Range;
117 import ucar.unidata.view.geoloc.MapProjectionDisplay;
118 import ucar.unidata.view.geoloc.MapProjectionDisplayJ3D;
119 import ucar.visad.display.DisplayMaster;
120 import ucar.visad.display.LineDrawing;
121 import ucar.visad.display.MapLines;
122 import ucar.visad.display.RGBDisplayable;
123 import ucar.visad.display.RubberBandBox;
124 import ucar.visad.display.XYDisplay;
125
126 import edu.wisc.ssec.mcidasv.data.hydra.CurveDrawer;
127 import edu.wisc.ssec.mcidasv.data.hydra.HistogramField;
128 import edu.wisc.ssec.mcidasv.data.hydra.HydraRGBDisplayable;
129 import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralData;
130 import edu.wisc.ssec.mcidasv.data.hydra.SubsetRubberBandBox;
131 import edu.wisc.ssec.mcidasv.data.hydra.LongitudeLatitudeCoordinateSystem;
132 import edu.wisc.ssec.mcidasv.data.hydra.Statistics;
133
134 public class ScatterDisplay extends DisplayControlImpl {
135
136 private static final Logger logger = LoggerFactory.getLogger(ScatterDisplay.class);
137
138 private Container container;
139 private FlatField X_field;
140 private FlatField Y_field;
141 private FlatField Area_field;
142 private double total_area;
143 private DisplayMaster scatterMaster = null;
144
145 private DisplayMaster dspMasterX;
146 private DisplayMaster dspMasterY;
147
148 private HistogramField histoField;
149
150 private FlatField mask_field;
151 private float[][] mask_range;
152 private float[][] scatterFieldRange;
153 private Data X_data;
154 private Data Y_data;
155 private String X_name;
156 private String Y_name;
157
158 private boolean cancel = false;
159
160 private ScatterDisplayable scatterMarkDsp;
161
162 private BoxCurveSwitch boxCurveSwitch;
163
164 public DataChoice dataChoiceX = null;
165
166 public DataChoice dataChoiceY = null;
167
168 public DataSelection dataSelectionX = null;
169
170 public DataSelection dataSelectionY = null;
171
172 JComponent ctwCompX;
173
174 JComponent ctwCompY;
175
176 ColorTableWidget ctw;
177
178 int n_selectors = 3;
179
180 List<ScatterBoxSelector> scatterBoxSelectors = new ArrayList<ScatterBoxSelector>();
181
182 List<ScatterCurveSelector> scatterCurveSelectors = new ArrayList<ScatterCurveSelector>();
183
184 List<ImageBoxSelector> imageXBoxSelectors = new ArrayList<ImageBoxSelector>();
185
186 List<ImageBoxSelector> imageYBoxSelectors = new ArrayList<ImageBoxSelector>();
187
188 List<ImageCurveSelector> imageXCurveSelectors = new ArrayList<ImageCurveSelector>();
189
190 List<ImageCurveSelector> imageYCurveSelectors = new ArrayList<ImageCurveSelector>();
191
192 JToggleButton[] selectorToggleButtons = new JToggleButton[n_selectors];
193 Color[] selectorColors = new Color[] {Color.magenta, Color.green, Color.blue};
194 float[][] maskColorPalette = new float[][] {{0.8f,0f,0f},{0f,0.8f,0f},{0.8f,0f,0.8f}};
195 float[][] markColorPalette = new float[][] {{1f,0.8f,0f,0f},{1f,0f,0.8f,0f},{1f,0.8f,0f,0.8f}};
196
197 JButton computeStatsButton;
198 MyStatsTable statsTable;
199
200 boolean selectByCurve = false;
201
202 public ScatterDisplay() {
203 super();
204 setHelpUrl("idv.controls.misc.scatteranalysiscontrol");
205 }
206
207
208 @Override public boolean init(List choices) throws VisADException, RemoteException {
209 if ((dataChoiceX != null) && (dataChoiceY != null)) {
210 setupFromUnpersistence();
211 }
212 else {
213 try {
214 setup();
215 } catch (VisADException vade) {
216 return false;
217 }
218 }
219
220 mask_field = new FlatField(
221 new FunctionType(((FunctionType)X_field.getType()).getDomain(), RealType.Generic),
222 X_field.getDomainSet());
223
224 int len = X_field.getDomainSet().getLength();
225 mask_range = new float[1][len];
226 for (int t=0; t<len; t++) {
227 mask_range[0][t] = Float.NaN;
228 }
229 mask_range[0][0] = 0; //- field should not be all missing
230 mask_field.setSamples(mask_range, false);
231
232 try {
233 histoField = new HistogramField(X_field, Y_field, mask_field, 100, 10);
234 }
235 catch (Exception e) {
236 e.printStackTrace();
237 }
238
239 Range rangeX = getImageRange(X_field);
240 Range rangeY = getImageRange(Y_field);
241 ColorTable clrTableX = getColorTable(X_field);
242 ColorTable clrTableY = getColorTable(Y_field);
243
244 dspMasterX = makeImageDisplay(getDataProjection(X_field), X_field, mask_field,
245 rangeX, clrTableX);
246
247 dspMasterY = makeImageDisplay(getDataProjection(Y_field), Y_field, mask_field,
248 rangeY, clrTableY);
249
250 dspMasterX.addDisplayListener(new DisplayListener() {
251 @Override public void displayChanged(final DisplayEvent e) {
252 double[] xProjection = dspMasterX.getProjectionMatrix();
253 double[] yProjection = dspMasterY.getProjectionMatrix();
254 if (xProjection.equals(yProjection))
255 return;
256
257 try {
258 dspMasterY.setProjectionMatrix(xProjection);
259 } catch (Exception ex) {
260 LogUtil.logException("dspMasterX.displayChanged", ex);
261 }
262 }
263 });
264
265 dspMasterY.addDisplayListener(new DisplayListener() {
266 @Override public void displayChanged(final DisplayEvent e) {
267 double[] xProjection = dspMasterX.getProjectionMatrix();
268 double[] yProjection = dspMasterY.getProjectionMatrix();
269 if (yProjection.equals(xProjection))
270 return;
271
272 try {
273 dspMasterX.setProjectionMatrix(yProjection);
274 } catch (Exception ex) {
275 LogUtil.logException("dspMasterX.displayChanged", ex);
276 }
277 }
278 });
279
280 X_name = ((((FunctionType)X_field.getType()).getFlatRange().getRealComponents())[0]).getName();
281 Y_name = ((((FunctionType)Y_field.getType()).getFlatRange().getRealComponents())[0]).getName();
282
283 if (statsTable != null) statsTable.setNames(X_name, Y_name);
284
285 Grid2DReadoutProbe probeX = new Grid2DReadoutProbe(X_field, dspMasterX);
286 Grid2DReadoutProbe probeY = new Grid2DReadoutProbe(Y_field, dspMasterY);
287 probeX.doMakeProbe(Color.red, dspMasterX);
288 probeY.doMakeProbe(Color.red, dspMasterY);
289
290 ImageControl dCntrl = new ImageControl((HydraRGBDisplayable)dspMasterX.getDisplayables(0), getDisplayConventions());
291 ctw = new ColorTableWidget(dCntrl, ColorTableManager.getManager(), clrTableX, rangeX);
292 ctwCompX = ctw.getLegendPanel(BOTTOM_LEGEND);
293 dCntrl.ctw = ctw;
294
295 dCntrl = new ImageControl((HydraRGBDisplayable)dspMasterY.getDisplayables(0), getDisplayConventions());
296 ctw = new ColorTableWidget(dCntrl, ColorTableManager.getManager(), clrTableY, rangeY);
297 ctwCompY = ctw.getLegendPanel(BOTTOM_LEGEND);
298 dCntrl.ctw = ctw;
299
300 return true;
301 }
302
303 public void setup() throws VisADException, RemoteException {
304 dataSelectionX = getDataSelection();
305 dataChoiceX = getDataChoice();
306 X_data = dataChoiceX.getData(dataSelectionX);
307
308 if (X_data instanceof FlatField) {
309 X_field = (FlatField) X_data;
310 } else if (X_data instanceof FieldImpl) {
311 X_field = (FlatField) ((FieldImpl)X_data).getSample(0);
312 }
313
314 popupDataDialog("select Y Axis field", container, false, null);
315
316 // if user canceled the popup, popupDataDialog will set the cancel flag
317 if (cancel) throw new VisADException("Scatter Display Canceled");
318
319 dataSelectionY = getDataSelection();
320 dataChoiceY = getDataChoice();
321
322 dataSelectionY.setGeoSelection(dataSelectionX.getGeoSelection());
323
324 Y_data = dataChoiceY.getData(dataSelectionY);
325
326 if (Y_data instanceof FlatField) {
327 Y_field = (FlatField) Y_data;
328 } else if (Y_data instanceof FieldImpl) {
329 Y_field = (FlatField) ((FieldImpl)Y_data).getSample(0);
330 }
331
332 if (!( X_field.getDomainSet().equals(Y_field.getDomainSet())))
333 {
334 Y_field = resample(X_field, Y_field);
335 }
336
337 Area_field = JPythonMethods.createAreaField(X_field);
338 statsTable = new MyStatsTable();
339
340 }
341
342 public void setupFromUnpersistence() throws VisADException, RemoteException {
343 X_data = dataChoiceX.getData(dataSelectionX);
344 if (X_data instanceof FlatField) {
345 X_field = (FlatField) X_data;
346 } else if (X_data instanceof FieldImpl) {
347 X_field = (FlatField) ((FieldImpl)X_data).getSample(0);
348 }
349
350 Y_data = dataChoiceY.getData(dataSelectionY);
351 if (Y_data instanceof FlatField) {
352 Y_field = (FlatField) Y_data;
353 } else if (X_data instanceof FieldImpl) {
354 Y_field = (FlatField) ((FieldImpl)Y_data).getSample(0);
355 }
356 }
357
358 @Override protected void popupDataDialog(final String dialogMessage,
359 Component from, boolean multiples,
360 List categories) {
361
362 List<DataChoice> choices = selectDataChoices(dialogMessage, from,
363 multiples, categories);
364 if ((choices == null) || (choices.size() == 0)) {
365 logger.debug("popupDataDialog, no data choice, user canceled");
366 cancel = true;
367 return;
368 }
369 final List clonedList =
370 DataChoice.cloneDataChoices((List)choices.get(0));
371 dataSelection = ((DataChoice) clonedList.get(0)).getDataSelection();
372 //- don't do this in a separate thread like the IDV does.
373 //- We want the dataChoice list updated before return.
374 try {
375 addNewData(clonedList);
376 } catch (Exception exc) {
377 logException("Selecting new data", exc);
378 }
379 }
380
381
382 @Override public void initDone() {
383 try {
384 DisplayMaster master = makeScatterDisplay();
385 for (int k=0; k<n_selectors; k++) {
386 scatterBoxSelectors.add(new ScatterBoxSelector(master, selectorColors[k], (float)k));
387 scatterCurveSelectors.add(new ScatterCurveSelector(master, selectorColors[k], (float)k));
388 }
389 master.draw();
390
391 for (int k=0; k<n_selectors; k++) {
392 SubsetRubberBandBox X_subsetBox =
393 new SubsetRubberBandBox(getIsLatLon(X_field), X_field,
394 ((MapProjectionDisplayJ3D)dspMasterX).getDisplayCoordinateSystem(), 1, false);
395 X_subsetBox.setColor(selectorColors[k]);
396
397 ImageBoxSelector markX = new ImageBoxSelector(X_subsetBox, X_field.getDomainSet(), dspMasterX, selectorColors[k], (float)k+1, statsTable);
398
399 SubsetRubberBandBox Y_subsetBox =
400 new SubsetRubberBandBox(getIsLatLon(Y_field), Y_field,
401 ((MapProjectionDisplayJ3D)dspMasterY).getDisplayCoordinateSystem(), 1, false);
402 Y_subsetBox.setColor(selectorColors[k]);
403 ImageBoxSelector markY = new ImageBoxSelector(Y_subsetBox, Y_field.getDomainSet(), dspMasterY, selectorColors[k], (float)k+1, statsTable);
404
405 markX.setOther(markY);
406 markY.setOther(markX);
407 imageXBoxSelectors.add(markX);
408 imageYBoxSelectors.add(markY);
409 }
410
411 for (int k=0; k<n_selectors; k++) {
412 CurveDrawer curveDraw = new CurveDrawer(RealType.Longitude, RealType.Latitude, 1);
413 curveDraw.setColor(selectorColors[k]);
414 curveDraw.setLineWidth(2);
415 ImageCurveSelector curveX = new ImageCurveSelector(curveDraw, X_field, dspMasterX, selectorColors[k], (float) k+1, statsTable);
416 curveX.setActive(false);
417 curveDraw.addAction(curveX);
418 curveX.setVisible(false);
419 dspMasterX.addDisplayable(curveDraw);
420
421 curveDraw = new CurveDrawer(RealType.Longitude, RealType.Latitude, 1);
422 curveDraw.setColor(selectorColors[k]);
423 curveDraw.setLineWidth(2);
424 ImageCurveSelector curveY = new ImageCurveSelector(curveDraw, Y_field, dspMasterY, selectorColors[k], (float) k+1, statsTable);
425 curveY.setActive(false);
426 curveDraw.addAction(curveY);
427 curveY.setVisible(false);
428 dspMasterY.addDisplayable(curveDraw);
429
430 curveX.setOther(curveY);
431 curveY.setOther(curveX);
432 imageXCurveSelectors.add(curveX);
433 imageYCurveSelectors.add(curveY);
434 }
435
436 for (int k=0; k<n_selectors; k++) {
437 JToggleButton jtog = selectorToggleButtons[k];
438
439 jtog.addActionListener(new ActionListener() {
440 @Override public void actionPerformed(ActionEvent e) {
441 int idx = Integer.valueOf(e.getActionCommand());
442 try {
443 for (int i=0; i<n_selectors; i++) {
444 ScatterBoxSelector boxSel = (ScatterBoxSelector) scatterBoxSelectors.get(i);
445 ImageBoxSelector imageXbox = (ImageBoxSelector) imageXBoxSelectors.get(i);
446 ImageBoxSelector imageYbox = (ImageBoxSelector) imageYBoxSelectors.get(i);
447 ScatterCurveSelector curveSel = (ScatterCurveSelector) scatterCurveSelectors.get(i);
448 ImageCurveSelector imageXcurve = (ImageCurveSelector) imageXCurveSelectors.get(i);
449 ImageCurveSelector imageYcurve = (ImageCurveSelector) imageYCurveSelectors.get(i);
450
451 if (i == idx) {
452 if (!selectorToggleButtons[i].isSelected()) {
453
454 if (statsTable != null) statsTable.resetValues(i);
455
456 boxSel.setActive(false);
457 boxSel.setVisible(false);
458 boxSel.reset();
459 imageXbox.setActive(false);
460 imageXbox.setVisible(false);
461 imageXbox.reset();
462 imageYbox.setActive(false);
463 imageYbox.setVisible(false);
464 imageYbox.reset();
465
466 curveSel.setActive(false);
467 curveSel.setVisible(false);
468 curveSel.reset();
469 imageXcurve.setActive(false);
470 imageXcurve.setVisible(false);
471 imageXcurve.reset();
472 imageYcurve.setActive(false);
473 imageYcurve.setVisible(false);
474 imageYcurve.reset();
475
476
477 }
478 boxSel.setActive(!getSelectByCurve());
479 boxSel.setVisible(!getSelectByCurve());
480 imageXbox.setActive(!getSelectByCurve());
481 imageXbox.setVisible(!getSelectByCurve());
482 imageYbox.setActive(!getSelectByCurve());
483 imageYbox.setVisible(!getSelectByCurve());
484
485 curveSel.setActive(getSelectByCurve());
486 curveSel.setVisible(getSelectByCurve());
487 imageXcurve.setActive(getSelectByCurve());
488 imageXcurve.setVisible(getSelectByCurve());
489 imageYcurve.setActive(getSelectByCurve());
490 imageYcurve.setVisible(getSelectByCurve());
491 }
492 else {
493 selectorToggleButtons[i].setSelected(false);
494 boxSel.setActive(false);
495 boxSel.setVisible(false);
496 imageXbox.setActive(false);
497 imageXbox.setVisible(false);
498 imageYbox.setActive(false);
499 imageYbox.setVisible(false);
500 curveSel.setActive(false);
501 curveSel.setVisible(false);
502 imageXcurve.setActive(false);
503 imageXcurve.setVisible(false);
504 imageYcurve.setActive(false);
505 imageYcurve.setVisible(false);
506 }
507 }
508 }
509 catch (Exception exc) {
510 System.out.println(exc);
511 }
512 }});
513
514 ScatterBoxSelector boxSel = (ScatterBoxSelector) scatterBoxSelectors.get(k);
515 ImageBoxSelector imageXbox = (ImageBoxSelector) imageXBoxSelectors.get(k);
516 ImageBoxSelector imageYbox = (ImageBoxSelector) imageYBoxSelectors.get(k);
517 ScatterCurveSelector curveSel = (ScatterCurveSelector) scatterCurveSelectors.get(k);
518 ImageCurveSelector imageXcurve = (ImageCurveSelector) imageXCurveSelectors.get(k);
519 ImageCurveSelector imageYcurve = (ImageCurveSelector) imageYCurveSelectors.get(k);
520
521 if (k == 0) {
522 jtog.setSelected(true);
523 boxSel.setActive(!getSelectByCurve());
524 boxSel.setVisible(!getSelectByCurve());
525 imageXbox.setActive(!getSelectByCurve());
526 imageXbox.setVisible(!getSelectByCurve());
527 imageYbox.setActive(!getSelectByCurve());
528 imageYbox.setVisible(!getSelectByCurve());
529
530 curveSel.setActive(getSelectByCurve());
531 curveSel.setVisible(getSelectByCurve());
532 imageXcurve.setActive(getSelectByCurve());
533 imageXcurve.setVisible(getSelectByCurve());
534 imageYcurve.setActive(getSelectByCurve());
535 imageYcurve.setVisible(getSelectByCurve());
536 }
537 else {
538 boxSel.setActive(false);
539 boxSel.setVisible(false);
540 imageXbox.setActive(false);
541 imageXbox.setVisible(false);
542 imageYbox.setActive(false);
543 imageYbox.setVisible(false);
544 curveSel.setActive(false);
545 curveSel.setVisible(false);
546 imageXcurve.setActive(false);
547 imageXcurve.setVisible(false);
548 imageYcurve.setActive(false);
549 imageYcurve.setVisible(false);
550 }
551 }
552 }
553 catch (Exception e) {
554 e.printStackTrace();
555 }
556 }
557
558 public DisplayMaster makeScatterDisplay() throws VisADException, RemoteException {
559
560 ScatterDisplayable scatterDsp = new ScatterDisplayable("scatter",
561 RealType.getRealType("mask"), markColorPalette, false);
562 float[] valsX = X_field.getFloats(false)[0];
563 float[] valsY = Y_field.getFloats(false)[0];
564 Integer1DSet set = new Integer1DSet(valsX.length);
565 FlatField scatter = new FlatField(
566 new FunctionType(RealType.Generic,
567 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), set);
568 float[] mask = new float[valsX.length];
569 for (int k=0; k<mask.length; k++) mask[k] = 0;
570 scatterFieldRange = new float[][] {valsX, valsY, mask};
571 scatter.setSamples(scatterFieldRange);
572 scatterDsp.setPointSize(2f);
573 scatterDsp.setRangeForColor(0,n_selectors);
574
575 float[] xRange = minmax(valsX);
576 float[] yRange = minmax(valsY);
577
578 scatterDsp.setData(scatter);
579
580 scatterMarkDsp = new ScatterDisplayable("scatter",
581 RealType.getRealType("mask"), markColorPalette, false);
582 set = new Integer1DSet(2);
583 scatter = new FlatField(
584 new FunctionType(RealType.Generic,
585 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), set);
586 scatterMarkDsp.setData(scatter);
587 scatterMarkDsp.setPointSize(2f);
588 scatterMarkDsp.setRangeForColor(0,n_selectors);
589
590 DisplayMaster master = scatterMaster;
591 ((XYDisplay)master).showAxisScales(true);
592 AxisScale scaleX = ((XYDisplay)master).getXAxisScale();
593 scaleX.setTitle(X_name);
594 AxisScale scaleY = ((XYDisplay)master).getYAxisScale();
595 scaleY.setTitle(Y_name);
596
597 ((XYDisplay)master).setXRange((double)xRange[0], (double)xRange[1]);
598 ((XYDisplay)master).setYRange((double)yRange[0], (double)yRange[1]);
599 master.addDisplayable(scatterDsp);
600 master.addDisplayable(scatterMarkDsp);
601
602 return master;
603 }
604
605
606 @Override public Container doMakeContents() {
607 JPanel pane = new JPanel(new GridLayout(1,3));
608
609 Component[] comps = new Component[] {null, null, null};
610 comps[0] = dspMasterX.getComponent();
611 comps[1] = dspMasterY.getComponent();
612 comps[2] = getScatterTabComponent();
613
614 JPanel panelX = new JPanel(new BorderLayout());
615 panelX.setBorder(new EmptyBorder(4,4,4,4));
616 panelX.add(comps[0], BorderLayout.CENTER);
617 panelX.add(ctwCompX, BorderLayout.SOUTH);
618
619 JPanel panelY = new JPanel(new BorderLayout());
620 panelY.setBorder(new EmptyBorder(4,4,4,4));
621 panelY.add(comps[1], BorderLayout.CENTER);
622 panelY.add(ctwCompY, BorderLayout.SOUTH);
623
624 JPanel panelS = new JPanel(new BorderLayout());
625 panelS.setBorder(new EmptyBorder(4,4,4,4));
626 panelS.add(comps[2], BorderLayout.CENTER);
627
628 pane.add(panelX);
629 pane.add(panelY);
630 pane.add(panelS);
631
632
633 JPanel buttonPanel = new JPanel();
634 buttonPanel.setLayout(new FlowLayout());
635 JRadioButton boxSelect = new JRadioButton("Box");
636 boxSelect.setSelected(true);
637 JRadioButton curveSelect = new JRadioButton("Curve");
638 ButtonGroup buttonGroup = new ButtonGroup();
639 buttonGroup.add(boxSelect);
640 buttonGroup.add(curveSelect);
641 buttonPanel.add(boxSelect);
642 buttonPanel.add(curveSelect);
643
644 boxCurveSwitch = new BoxCurveSwitch();
645 boxSelect.addActionListener(boxCurveSwitch);
646 curveSelect.addActionListener(boxCurveSwitch);
647
648
649 JPanel toggleButtonPanel = new JPanel(new FlowLayout());
650 for (int k=0; k<n_selectors; k++) {
651 JToggleButton jtog =
652 new JToggleButton(
653 new ImageIcon(getClass().getResource("/edu/wisc/ssec/mcidasv/resources/icons/buttons/subset12.jpg")));
654 jtog.setBorder(new CompoundBorder(new LineBorder(selectorColors[k],2), new EmptyBorder(4,4,4,4)));
655 jtog.setActionCommand(String.valueOf(k));
656 toggleButtonPanel.add(jtog);
657 selectorToggleButtons[k] = jtog;
658 }
659
660 buttonPanel.add(toggleButtonPanel);
661
662 JButton computeStatsButton = new JButton("compute statistics");
663
664 computeStatsButton.addActionListener(new ActionListener() {
665 public void actionPerformed(final ActionEvent e) {
666
667 if (statsTable == null) {
668 statsTable = new MyStatsTable();
669 }
670
671 statsTable.setIsShowing();
672 statsTable.setFields(X_field, Y_field,0);
673 }
674 });
675
676 buttonPanel.add(computeStatsButton);
677
678 //-container = pane;
679 JPanel new_pane = new JPanel(new BorderLayout());
680 new_pane.add(pane, BorderLayout.CENTER);
681 new_pane.add(buttonPanel, BorderLayout.SOUTH);
682 container = new_pane;
683 return container;
684 }
685
686
687 protected Component getScatterTabComponent() {
688 try {
689 scatterMaster = new XYDisplay("Scatter", RealType.XAxis, RealType.YAxis);
690 } catch (Exception e) {
691 e.printStackTrace();
692 }
693 return scatterMaster.getComponent();
694 }
695
696 public DisplayMaster makeImageDisplay(MapProjection mapProj, FlatField image,
697 FlatField mask_image, Range imageRange, ColorTable colorTable)
698 throws VisADException, RemoteException {
699 MapProjectionDisplayJ3D mapProjDsp;
700 DisplayMaster dspMaster;
701
702 mapProjDsp = new MapProjectionDisplayJ3D(MapProjectionDisplay.MODE_2Din3D);
703 mapProjDsp.enableRubberBanding(false);
704 dspMaster = mapProjDsp;
705 mapProjDsp.setMapProjection(mapProj);
706
707 RealType imageRangeType =
708 (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0];
709
710 boolean alphaflag = false;
711 HydraRGBDisplayable imageDsp = new HydraRGBDisplayable("image", imageRangeType, null, alphaflag, null);
712
713 imageDsp.setData(image);
714 dspMaster.addDisplayable(imageDsp);
715 addMapDisplayables(mapProjDsp);
716
717 if (mask_image != null) {
718 RGBDisplayable maskDsp =
719 new ScatterDisplayable("mask", RealType.Generic, maskColorPalette, false);
720 maskDsp.setData(mask_image);
721 maskDsp.setRangeForColor(0, n_selectors-1);
722 dspMaster.addDisplayable(maskDsp);
723 }
724
725 dspMaster.draw();
726
727 ScalarMap colorMap = imageDsp.getColorMap();
728 colorMap.setRange(imageRange.getMin(), imageRange.getMax());
729 BaseColorControl clrCntrl = (BaseColorControl) colorMap.getControl();
730 float[][] ct = colorTable.getColorTable();
731
732 if ( !(alphaflag) && (ct.length == 4) ) {
733 float[][] new_ct = new float[3][];
734 new_ct[0] = ct[0];
735 new_ct[1] = ct[1];
736 new_ct[2] = ct[2];
737 ct = new_ct;
738 }
739
740 clrCntrl.setTable(ct);
741
742 return dspMaster;
743 }
744
745 public Range getImageRange(FlatField image)
746 throws VisADException, RemoteException {
747 DisplayConventions dc = getDisplayConventions();
748 Range[] range = GridUtil.fieldMinMax(image);
749 Range imageRange = range[0];
750 RealType imageRangeType =
751 (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0];
752 String canonicalName = DataAlias.aliasToCanonical(imageRangeType.getName());
753 Range dfltRange = dc.getParamRange(canonicalName, null);
754
755 if (dfltRange == null) {
756 imageRange = range[0];
757 }
758 else if ((imageRange.getMax() - imageRange.getMin()) < (dfltRange.getMax() - dfltRange.getMin())) {
759 }
760 else {
761 imageRange = dfltRange;
762 }
763 return imageRange;
764 }
765
766 public ColorTable getColorTable(FlatField image)
767 throws VisADException, RemoteException {
768 RealType imageRangeType =
769 (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0];
770 DisplayConventions dc = getDisplayConventions();
771 return dc.getParamColorTable(imageRangeType.getName());
772 }
773
774
775 public MapProjection getDataProjection(FlatField image)
776 throws VisADException, RemoteException {
777 MapProjection mp = null;
778 //- get MapProjection from incoming image. If none, use default method
779 FunctionType fnc_type = (FunctionType) image.getType();
780 RealTupleType rtt = fnc_type.getDomain();
781 CoordinateSystem cs = rtt.getCoordinateSystem();
782 Set domainSet = image.getDomainSet();
783
784 if (cs instanceof visad.CachingCoordinateSystem) {
785 cs = ((visad.CachingCoordinateSystem)cs).getCachedCoordinateSystem();
786 }
787
788 if (cs instanceof MapProjection) {
789 return (MapProjection) cs;
790 }
791 else if (cs instanceof LongitudeLatitudeCoordinateSystem) {
792 Rectangle2D rect = MultiSpectralData.getLonLatBoundingBox(image);
793 try {
794 mp = new LambertAEA(rect);
795 } catch (Exception e) {
796 System.out.println(" getDataProjection"+e);
797 }
798 return mp;
799 }
800
801 float minLon = Float.NaN;
802 float minLat = Float.NaN;
803 float delLon = Float.NaN;
804 float delLat = Float.NaN;
805
806 if (domainSet instanceof LinearLatLonSet) {
807 MathType type0 = ((SetType)domainSet.getType()).getDomain().getComponent(0);
808 int latI = RealType.Latitude.equals(type0) ? 0 : 1;
809 int lonI = (latI == 1) ? 0 : 1;
810
811 float[] min = ((LinearLatLonSet)domainSet).getLow();
812 float[] max = ((LinearLatLonSet)domainSet).getHi();
813 minLon = min[lonI];
814 minLat = min[latI];
815 delLon = max[lonI] - min[lonI];
816 delLat = max[latI] - min[latI];
817
818 try {
819 mp = new TrivialMapProjection(RealTupleType.SpatialEarth2DTuple,
820 new Rectangle2D.Float(minLon, minLat, delLon, delLat));
821 } catch (Exception e) {
822 logException("MultiSpectralControl.getDataProjection", e);
823 }
824
825 return mp;
826 }
827 else if (domainSet instanceof Gridded2DSet) {
828 rtt = ((SetType)domainSet.getType()).getDomain();
829 rtt = RealTupleType.SpatialEarth2DTuple;
830 if (!(rtt.equals(RealTupleType.SpatialEarth2DTuple) || rtt.equals(RealTupleType.LatitudeLongitudeTuple))) {
831 minLon = -180f;
832 minLat = -90f;
833 delLon = 360f;
834 delLat = 180f;
835 }
836 else {
837 int latI = rtt.equals(RealTupleType.SpatialEarth2DTuple) ? 1 : 0;
838 int lonI = (latI == 1) ? 0 : 1;
839
840 float[] min = ((Gridded2DSet)domainSet).getLow();
841 float[] max = ((Gridded2DSet)domainSet).getHi();
842 minLon = min[lonI];
843 minLat = min[latI];
844 delLon = max[lonI] - min[lonI];
845 delLat = max[latI] - min[latI];
846 }
847 }
848
849 try {
850 mp = new TrivialMapProjection(RealTupleType.SpatialEarth2DTuple,
851 new Rectangle2D.Float(minLon, minLat, delLon, delLat));
852 } catch (Exception e) {
853 logException("MultiSpectralControl.getDataProjection", e);
854 }
855
856 return mp;
857 }
858
859 public void addMapDisplayables(MapProjectionDisplayJ3D mapProjDsp)
860 throws VisADException, RemoteException {
861 MapLines mapLines = new MapLines("maplines");
862 URL mapSource =
863 mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPU");
864 try {
865 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
866 mapLines.setMapLines(mapAdapter.getData());
867 mapLines.setColor(java.awt.Color.cyan);
868 mapProjDsp.addDisplayable(mapLines);
869 } catch (Exception excp) {
870 System.out.println("Can't open map file " + mapSource);
871 System.out.println(excp);
872 }
873
874 mapLines = new MapLines("maplines");
875 mapSource =
876 mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPW");
877 try {
878 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
879 mapLines.setMapLines(mapAdapter.getData());
880 mapLines.setColor(java.awt.Color.cyan);
881 mapProjDsp.addDisplayable(mapLines);
882 } catch (Exception excp) {
883 System.out.println("Can't open map file " + mapSource);
884 System.out.println(excp);
885 }
886
887 mapLines = new MapLines("maplines");
888 mapSource =
889 mapProjDsp.getClass().getResource("/auxdata/maps/OUTLHPOL");
890 try {
891 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
892 mapLines.setMapLines(mapAdapter.getData());
893 mapLines.setColor(java.awt.Color.cyan);
894 mapProjDsp.addDisplayable(mapLines);
895 } catch (Exception excp) {
896 System.out.println("Can't open map file " + mapSource);
897 System.out.println(excp);
898 }
899 }
900
901 public boolean getSelectByCurve() {
902 return selectByCurve;
903 }
904
905 private FlatField resample(FlatField X_field, FlatField Y_field) throws VisADException, RemoteException {
906
907 RealTupleType X_domainRef = null;
908 RealTupleType Y_domainRef = null;
909 float[][] coords = null;
910 int[] indexes = null;
911 float[][] Yvalues = Y_field.getFloats(false);
912 float[][] Xsamples = ((SampledSet)X_field.getDomainSet()).getSamples(false);
913
914 CoordinateSystem X_cs = X_field.getDomainCoordinateSystem();
915 if (X_cs == null) {
916 RealTupleType X_domain = ((FunctionType)X_field.getType()).getDomain();
917 }
918 else {
919 X_domainRef = X_cs.getReference();
920 }
921
922 CoordinateSystem Y_cs = Y_field.getDomainCoordinateSystem();
923 if (Y_cs == null) {
924 RealTupleType Y_domain = ((FunctionType)Y_field.getType()).getDomain();
925 }
926 else {
927 Y_domainRef = Y_cs.getReference();
928 }
929
930 if ( X_domainRef != null && Y_domainRef != null) {
931 Xsamples = X_cs.toReference(Xsamples);
932 coords = Y_cs.fromReference(Xsamples);
933 indexes = ((SampledSet)Y_field.getDomainSet()).valueToIndex(coords);
934 }
935 else if ( X_domainRef == null && Y_domainRef != null ) {
936 Xsamples = Y_cs.fromReference(Xsamples);
937 indexes = ((SampledSet)Y_field.getDomainSet()).valueToIndex(Xsamples);
938 }
939 else if ( X_domainRef != null && Y_domainRef == null) {
940 Xsamples = X_cs.toReference(Xsamples);
941 Gridded2DSet domSet = (Gridded2DSet) Y_field.getDomainSet();
942
943 // TODO this is a hack for the longitude range problem
944 float[] hi = domSet.getHi();
945 if (hi[0] <= 180f) {
946 for (int t=0; t<Xsamples[0].length; t++) {
947 if (Xsamples[0][t] > 180f) Xsamples[0][t] -=360;
948 }
949 }
950
951 indexes = ((SampledSet)Y_field.getDomainSet()).valueToIndex(Xsamples);
952 }
953 else if (X_domainRef == null && Y_domainRef == null) {
954 Gridded2DSet domSet = (Gridded2DSet) Y_field.getDomainSet();
955 indexes = domSet.valueToIndex(Xsamples);
956 }
957
958 float[][] new_values = new float[1][indexes.length];
959 for (int k=0; k<indexes.length; k++) {
960 new_values[0][k] = Float.NaN;
961 if (indexes[k] >= 0) {
962 new_values[0][k] = Yvalues[0][indexes[k]];
963 }
964 }
965
966 FunctionType ftype = new FunctionType(((FunctionType)X_field.getType()).getDomain(),
967 ((FunctionType)Y_field.getType()).getRange());
968 Y_field = new FlatField(ftype, X_field.getDomainSet());
969 Y_field.setSamples(new_values);
970
971 return Y_field;
972 }
973
974
975 //For creating a non-editable JTable
976 private class MyStatsTable extends AbstractTableModel {
977 String [][] data;
978 JTable table;
979 JFrame statsWindow;
980 int numCols;
981 boolean isShowing = false;
982 Color[] coltab = {new Color(0xf0f0f0), new Color(0xffd0ff),
983 new Color(0xd0ffd0), new Color(0xc0d0ff)};
984
985 final int maxCols = 9;
986 String[] colNames = {"Stats Parameter","Whole Field X","Whole Field Y",
987 "Magenta X","Magenta Y", "Green X","Green Y","Blue X","Blue Y"};
988
989 final int maxRows = 13;
990 final String[] rowNames = {"Maximum","Minimum",
991 "Number of points","Mean","Median","Variance","Kurtosis",
992 "Std Dev","Correlation","Difference Maximum",
993 "Difference Minimum","Difference Mean","Area [km^2]"};
994
995 MyStatsTable() { super();
996 data = new String[maxRows][maxCols];
997 numCols = 1;
998
999 for (int i=0; i<maxRows; i++) {
1000 data[i][0] = rowNames[i];
1001 for (int j=1; j<maxCols; j++) {
1002 data[i][j] = " ";
1003 }
1004 }
1005
1006
1007 table = new JTable(this) {
1008 public Component prepareRenderer(
1009 TableCellRenderer renderer, int row, int col) {
1010 Component comp = super.prepareRenderer(renderer, row, col);
1011 Color c = Color.white;
1012 if (col == 0) c = coltab[0];
1013 if (col == 3 || col == 4) c = coltab[1];
1014 if (col == 5 || col == 6) c = coltab[2];
1015 if (col == 7 || col == 8) c = coltab[3];
1016 comp.setBackground(c);
1017 return comp;
1018 }
1019
1020 };
1021 table.setFillsViewportHeight(true);
1022 table.setPreferredScrollableViewportSize(new Dimension(620,220));
1023 table.setRowSelectionAllowed(true);
1024 table.setColumnSelectionAllowed(false);
1025
1026 JButton saveStatsButt = new JButton("Save As CSV");
1027 JScrollPane sp = new JScrollPane(table);
1028 statsWindow = new JFrame("Scatter Statistics");
1029 statsWindow.setLayout(new BorderLayout());
1030 statsWindow.getContentPane().add(sp,BorderLayout.NORTH);
1031 JPanel bpan = new JPanel(new FlowLayout());
1032 bpan.add(saveStatsButt);
1033 statsWindow.getContentPane().add(bpan,BorderLayout.SOUTH);
1034 statsWindow.setSize(650,340);
1035 statsWindow.pack();
1036 statsWindow.addWindowListener(new WindowAdapter() {
1037 public void windowClosing(WindowEvent e) {
1038 isShowing = false;
1039 }
1040 });
1041
1042 saveStatsButt.addActionListener(new ActionListener() {
1043 public void actionPerformed(final ActionEvent e) {
1044 JFileChooser chzr = new JFileChooser();
1045 FileFilter filt = new FileNameExtensionFilter("csv","txt");
1046 chzr.addChoosableFileFilter(filt);
1047 int rv = chzr.showSaveDialog(statsWindow);
1048 if (rv == JFileChooser.APPROVE_OPTION) {
1049 try {
1050 File fpw = chzr.getSelectedFile();
1051 statsWindow.setTitle("Scatter Statistics saved to "+fpw.toString());
1052 PrintWriter pw = new PrintWriter(fpw);
1053 String line = "";
1054 for (int k=0; k<colNames.length; k++) {
1055 if (k != 0) line = line + ",";
1056 line = line + colNames[k];
1057 }
1058 pw.println(line);
1059
1060 for (int i=0; i<data.length; i++) {
1061 line = "";
1062 for (int j=0; j<data[i].length; j++) {
1063 if (j != 0) line = line+",";
1064 line = line+data[i][j];
1065 }
1066 pw.println(line);
1067 }
1068 pw.flush();
1069 pw.close();
1070 } catch (Exception epw) {
1071 statsWindow.setTitle("Scatter Statistics: File not saved");
1072 }
1073
1074 }
1075
1076 }
1077 });
1078
1079 isShowing = false;
1080 statsWindow.setVisible(false);
1081 }
1082
1083 public void setIsShowing() {
1084 isShowing = true;
1085 }
1086
1087 public void resetValues(int col) {
1088 for (int i=0; i<maxRows; i++) {
1089 int c = 2*col + 3;
1090 data[i][c] = " ";
1091 data[i][c+1] = " ";
1092 }
1093 fireTableStructureChanged();
1094 }
1095
1096 public void setNames(String xn, String yn) {
1097 colNames[1] = colNames[3] = colNames[5] = colNames[7] =xn;
1098 colNames[2] = colNames[4] = colNames[6] = colNames[8] =yn;
1099 }
1100
1101 // fx, fy are Fields, col = 0,1,2,3 (all, red, green, blue)
1102 public void setFields(FlatField fx, FlatField fy, int col) {
1103 statsWindow.setTitle("Scatter Statistics");
1104 try {
1105 Statistics sx = new Statistics(fx);
1106 Statistics sy = new Statistics(fy);
1107 Statistics diff = new Statistics((FlatField)fx.subtract(fy));
1108
1109 int c = 2*col + 1;
1110 data[0][c] = fmtMe(((Real)sx.max()).getValue());
1111 data[0][c+1] = fmtMe(((Real)sy.max()).getValue());
1112
1113 data[1][c] = fmtMe(((Real)sx.min()).getValue());
1114 data[1][c+1] = fmtMe(((Real)sy.min()).getValue());
1115
1116 data[2][c] = String.format("%d",sx.numPoints());
1117 data[2][c+1] = String.format("%d",sy.numPoints());
1118
1119 data[3][c] = fmtMe(((Real)sx.mean()).getValue());
1120 data[3][c+1] = fmtMe(((Real)sy.mean()).getValue());
1121
1122 data[4][c] = fmtMe(((Real)sx.median()).getValue());
1123 data[4][c+1] = fmtMe(((Real)sy.median()).getValue());
1124
1125 data[5][c] = fmtMe(((Real)sx.variance()).getValue());
1126 data[5][c+1] = fmtMe(((Real)sy.variance()).getValue());
1127
1128 data[6][c] = fmtMe(((Real)sx.kurtosis()).getValue());
1129 data[6][c+1] = fmtMe(((Real)sy.kurtosis()).getValue());
1130
1131 data[7][c] = fmtMe(((Real)sx.standardDeviation()).getValue());
1132 data[7][c+1] = fmtMe(((Real)sy.standardDeviation()).getValue());
1133
1134 data[8][c] = fmtMe(((Real)sx.correlation(fy)).getValue());
1135 data[8][c+1] = " ";
1136
1137 data[9][c] = fmtMe(((Real)diff.max()).getValue());
1138 data[9][c+1] = " ";
1139
1140 data[10][c] = fmtMe(((Real)diff.min()).getValue());
1141 data[10][c+1] = " ";
1142
1143 data[11][c] = fmtMe(((Real)diff.mean()).getValue());
1144 data[11][c+1] = " ";
1145
1146 if (c == 1) {
1147 data[12][c] = " ";
1148 } else {
1149 data[12][c] = fmtMe(total_area);
1150 }
1151 data[12][c+1] = " ";
1152
1153 if (c+2 > numCols) numCols = c+2;
1154 fireTableStructureChanged();
1155
1156 } catch (VisADException exc) {
1157 System.out.println(exc.getMessage());
1158 } catch (Exception exc) {
1159 exc.printStackTrace();
1160 }
1161
1162 if (isShowing) statsWindow.setVisible(true);
1163 }
1164
1165 private String fmtMe(double val) {
1166
1167 if (Math.abs(val) == 0.0) {
1168 return "0.00";
1169
1170 } else if (Math.abs(val) > 9999.9 || Math.abs(val) < .0010) {
1171 return String.format("%.6e", val);
1172
1173 } else if (Math.abs(val) < 1.0) {
1174 return String.format("%.5f", val);
1175
1176 } else if (Math.abs(val) < 10.0) {
1177 return String.format("%.3f", val);
1178
1179 } else {
1180 return String.format("%.2f", val);
1181 }
1182 }
1183
1184 public void setPoints(float[][] markScatter, int len, int indx) {
1185 try {
1186 Integer1DSet sdset = new Integer1DSet(len);
1187 FlatField scattX = new FlatField(
1188 new FunctionType(RealType.Generic, RealType.Generic), sdset);
1189
1190 float[][] scattValsX = new float[1][len];
1191 System.arraycopy(markScatter[0],0,scattValsX[0],0,len);
1192 scattX.setSamples(scattValsX, false);
1193
1194 FlatField scattY = new FlatField(
1195 new FunctionType(RealType.Generic, RealType.Generic), sdset);
1196 float[][] scattValsY = new float[1][len];
1197 System.arraycopy(markScatter[1],0,scattValsY[0],0,len);
1198 scattY.setSamples(scattValsY, false);
1199
1200 setFields(scattX, scattY, indx);
1201
1202 } catch (Exception esd) {
1203 esd.printStackTrace();
1204 }
1205 }
1206
1207 public int getRowCount() {
1208 return maxRows;
1209 }
1210 public int getColumnCount() {
1211 return numCols;
1212 }
1213 public String getValueAt(int row, int col) {
1214 return data[row][col];
1215 }
1216 public String getColumnName(int col) {
1217 return colNames[col];
1218 }
1219 }
1220
1221
1222 private class ScatterDisplayable extends RGBDisplayable {
1223 ScatterDisplayable(String name, RealType rgbRealType, float[][] colorPalette, boolean alphaflag)
1224 throws VisADException, RemoteException {
1225 super(name, rgbRealType, colorPalette, alphaflag);
1226 }
1227 }
1228
1229 private class ImageControl extends DisplayControlImpl {
1230 HydraRGBDisplayable rgbDisp;
1231 DisplayConventions dc;
1232 ColorTableWidget ctw;
1233
1234 ImageControl(HydraRGBDisplayable rgbDisp, DisplayConventions dc) {
1235 super();
1236 this.rgbDisp = rgbDisp;
1237 this.dc = dc;
1238 }
1239
1240 @Override public void setRange(Range r) throws VisADException, RemoteException {
1241 if (r != null) {
1242 rgbDisp.setRangeForColor(r.getMin(), r.getMax());
1243 }
1244 }
1245
1246 @Override public DisplayConventions getDisplayConventions() {
1247 return dc;
1248 }
1249
1250 @Override public void setColorTable(ColorTable ct) {
1251 try {
1252 ctw.setColorTable(ct);
1253 ScalarMap colorMap = rgbDisp.getColorMap();
1254 BaseColorControl clrCntrl = (BaseColorControl) colorMap.getControl();
1255
1256 // Force incoming color dimension to that of the colorMap
1257 //
1258 int numComps = clrCntrl.getNumberOfComponents();
1259 float[][] clrTable = ct.getColorTable();
1260 float[][] newTable = null;
1261 if (numComps != clrTable.length) {
1262 if (numComps < clrTable.length) {
1263 newTable = new float[numComps][clrTable[0].length];
1264 for (int k=0; k<numComps; k++) {
1265 System.arraycopy(clrTable[k], 0, newTable[k], 0, newTable[0].length);
1266 }
1267 }
1268 else if (numComps > clrTable.length) {
1269 newTable = new float[numComps][clrTable[0].length];
1270 for (int k=0; k<clrTable.length; k++) {
1271 System.arraycopy(clrTable[k], 0, newTable[k], 0, newTable[0].length);
1272 }
1273 newTable[3] = new float[clrTable[0].length];
1274 }
1275 } else {
1276 newTable = new float[numComps][clrTable[0].length];
1277 for (int k = 0; k < clrTable.length; k++) {
1278 System.arraycopy(clrTable[k], 0, newTable[k], 0, newTable[0].length);
1279 }
1280 }
1281 clrCntrl.setTable(newTable);
1282 }
1283 catch (Exception e) {
1284 LogUtil.logException("Problem changing color table", e);
1285 }
1286 }
1287 }
1288
1289 private class ImageCurveSelector extends CellImpl implements DisplayListener {
1290 boolean init = false;
1291 CurveDrawer curveDraw;
1292 DisplayMaster dspMaster;
1293 Gridded2DSet domainSet;
1294 CoordinateSystem cs;
1295 int domainLen_0;
1296 int domainLen_1;
1297 ImageCurveSelector other;
1298 UnionSet last_uSet = null;
1299 boolean imageLatLon = false;
1300 boolean active = true;
1301 float maskVal;
1302 LineDrawing lastCurve;
1303 MyStatsTable myTable = null;
1304 int myTableIndex = 0;
1305
1306 ImageCurveSelector(CurveDrawer curveDraw, FlatField image, DisplayMaster master, Color color, float maskVal, MyStatsTable mst)
1307 throws VisADException, RemoteException {
1308 this.curveDraw = curveDraw;
1309 this.maskVal = maskVal;
1310 this.myTable = mst;
1311 myTableIndex = 0;
1312 if (color == Color.magenta) myTableIndex = 1;
1313 if (color == Color.green) myTableIndex = 2;
1314 if (color == Color.blue) myTableIndex = 3;
1315 dspMaster = master;
1316 dspMaster.addDisplayListener(this);
1317 domainSet = (Gridded2DSet) image.getDomainSet();
1318 int[] lens = domainSet.getLengths();
1319 domainLen_0 = lens[0];
1320 domainLen_1 = lens[1];
1321 cs = ((FunctionType)image.getType()).getDomain().getCoordinateSystem();
1322 RealTupleType reference = null;
1323 if (cs != null) {
1324 reference = cs.getReference();
1325 }
1326 else {
1327 reference = ((SetType)domainSet.getType()).getDomain();
1328 }
1329 RealType[] rtypes = reference.getRealComponents();
1330 if (rtypes[0].equals(RealType.Latitude)) imageLatLon = true;
1331 lastCurve = new LineDrawing("lastCurve");
1332 lastCurve.setColor(color);
1333 lastCurve.setLineWidth(2);
1334 master.addDisplayable(lastCurve);
1335 }
1336
1337 @Override public void displayChanged(DisplayEvent de)
1338 throws VisADException, RemoteException {
1339 if ((de.getId() == DisplayEvent.MOUSE_RELEASED) && (active)) {
1340 UnionSet uSet = curveDraw.getCurves();
1341 if (uSet == last_uSet) return;
1342 SampledSet[] sets = uSet.getSets();
1343 int s_idx = sets.length-1;
1344 float[][] crv;
1345
1346 if (cs != null) {
1347 crv = sets[s_idx].getSamples();
1348 if (imageLatLon) {
1349 float[] tmp = crv[0];
1350 crv[0] = crv[1];
1351 crv[1] = tmp;
1352 }
1353 crv = cs.fromReference(crv);
1354 crv = domainSet.valueToGrid(crv);
1355 }
1356 else {
1357 crv = sets[s_idx].getSamples();
1358 crv = domainSet.valueToGrid(crv);
1359 }
1360
1361 float[][] onImage = new float[2][crv[0].length];
1362 int cnt = 0;
1363 for (int i=0; i<crv[0].length; i++) {
1364 if ( ((crv[0][i] >= 0)&&(crv[0][i] <= domainLen_0)) &&
1365 ((crv[1][i] >= 0)&&(crv[1][i] <= domainLen_1)) ) {
1366 onImage[0][cnt] = crv[0][i];
1367 onImage[1][cnt] = crv[1][i];
1368 cnt++;
1369 }
1370 }
1371 uSet = new UnionSet(new SampledSet[] {sets[s_idx]});
1372 last_uSet = uSet;
1373 lastCurve.setData(last_uSet);
1374 curveDraw.setCurves(uSet);
1375 other.updateCurve(sets[s_idx]);
1376
1377 if (cnt == 0) {
1378 return;
1379 }
1380
1381 float[][] tmp = new float[2][cnt];
1382 System.arraycopy(onImage[0], 0, tmp[0], 0, cnt);
1383 System.arraycopy(onImage[1], 0, tmp[1], 0, cnt);
1384 onImage = tmp;
1385
1386 float[] minmaxvals = minmax(onImage[0]);
1387 int low_0 = Math.round(minmaxvals[0]);
1388 int hi_0 = Math.round(minmaxvals[1]);
1389 minmaxvals = minmax(onImage[1]);
1390 int low_1 = Math.round(minmaxvals[0]);
1391 int hi_1 = Math.round(minmaxvals[1]);
1392
1393 int len_0 = (hi_0 - low_0) + 1;
1394 int len_1 = (hi_1 - low_1) + 1;
1395 int len = len_0*len_1;
1396
1397 tmp = new float[3][len];
1398 int[] tmpsel = new int[len];
1399
1400 int num_inside = 0;
1401 for (int j=0; j<len_1; j++) {
1402 for (int i=0; i<len_0; i++) {
1403 int idx = (j+low_1)*domainLen_0 + (i+low_0);
1404 float x = (float) (i + low_0);
1405 float y = (float) (j + low_1);
1406 if (DelaunayCustom.inside(crv, x, y)) {
1407 tmp[0][num_inside] = scatterFieldRange[0][idx];
1408 tmp[1][num_inside] = scatterFieldRange[1][idx];
1409 tmp[2][num_inside] = maskVal;
1410 tmpsel[num_inside] = idx;
1411 num_inside++;
1412 }
1413 }
1414 }
1415 len = num_inside;
1416 float[][] markScatter = new float[3][len];
1417 System.arraycopy(tmp[0], 0, markScatter[0], 0, len);
1418 System.arraycopy(tmp[1], 0, markScatter[1], 0, len);
1419 System.arraycopy(tmp[2], 0, markScatter[2], 0, len);
1420
1421
1422 int last_len = 0;
1423 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false);
1424 tmp = new float[3][lastMark[0].length];
1425 for (int k=0; k<lastMark[0].length; k++) {
1426 if (lastMark[2][k] != maskVal) {
1427 tmp[0][last_len] = lastMark[0][k];
1428 tmp[1][last_len] = lastMark[1][k];
1429 tmp[2][last_len] = lastMark[2][k];
1430 last_len++;
1431 }
1432 }
1433
1434 float[][] newMarkScatter = new float[3][len+last_len];
1435 System.arraycopy(tmp[0], 0, newMarkScatter[0], 0, last_len);
1436 System.arraycopy(tmp[1], 0, newMarkScatter[1], 0, last_len);
1437 System.arraycopy(tmp[2], 0, newMarkScatter[2], 0, last_len);
1438 System.arraycopy(markScatter[0], 0, newMarkScatter[0], last_len, len);
1439 System.arraycopy(markScatter[1], 0, newMarkScatter[1], last_len, len);
1440 System.arraycopy(markScatter[2], 0, newMarkScatter[2], last_len, len);
1441
1442 Integer1DSet dset = new Integer1DSet(len+last_len);
1443 FlatField scatterFieldMark = new FlatField(
1444 new FunctionType(RealType.Generic,
1445 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset);
1446
1447 scatterFieldMark.setSamples(newMarkScatter, false);
1448 scatterMarkDsp.setData(scatterFieldMark);
1449
1450 if (myTable != null) {
1451 int[] selected = new int[len];
1452 System.arraycopy(tmpsel, 0, selected, 0, len);
1453 total_area = JPythonMethods.computeSum(Area_field, selected);
1454 myTable.setPoints(markScatter, len, myTableIndex);
1455 }
1456
1457 }
1458 }
1459
1460 public void setActive(boolean active) {
1461 this.active = active;
1462 }
1463
1464 public void reset() throws VisADException, RemoteException {
1465
1466 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false);
1467 float[][] tmp = new float[3][lastMark[0].length];
1468 int cnt = 0;
1469 for (int k=0; k<lastMark[0].length; k++) {
1470 if (lastMark[2][k] != maskVal) {
1471 tmp[0][cnt] = lastMark[0][k];
1472 tmp[1][cnt] = lastMark[1][k];
1473 tmp[2][cnt] = lastMark[2][k];
1474 cnt++;
1475 }
1476 }
1477
1478 RealTupleType type = ((SetType)curveDraw.getCurves().getType()).getDomain();
1479 curveDraw.setCurves(new UnionSet(new Gridded2DSet[]{
1480 new Gridded2DSet(type, new float[][] {
1481 { 0.0f }, { 0.0f }}, 1) }));
1482
1483 lastCurve.setData(new UnionSet(new Gridded2DSet[]{
1484 new Gridded2DSet(type, new float[][] {
1485 { 0.0f }, { 0.0f }}, 1) }));
1486
1487 FlatField scatterFieldMark = null;
1488 if (cnt == 0) {
1489 Integer1DSet dset = new Integer1DSet(2);
1490 scatterFieldMark = new FlatField(
1491 new FunctionType(RealType.Generic,
1492 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset);
1493 float[][] markScatter = new float[3][2];
1494 for (int k=0; k<2; k++) {
1495 markScatter[0][k] = scatterFieldRange[0][k];
1496 markScatter[1][k] = scatterFieldRange[1][k];
1497 markScatter[2][k] = 0;
1498 }
1499 scatterFieldMark.setSamples(markScatter, false);
1500 }
1501 else {
1502 Integer1DSet dset = new Integer1DSet(cnt);
1503 scatterFieldMark = new FlatField(
1504 new FunctionType(RealType.Generic,
1505 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset);
1506 float[][] markScatter = new float[3][cnt];
1507 for (int k=0; k<cnt; k++) {
1508 markScatter[0][k] = tmp[0][k];
1509 markScatter[1][k] = tmp[1][k];
1510 markScatter[2][k] = tmp[2][k];
1511 }
1512 scatterFieldMark.setSamples(markScatter, false);
1513 }
1514
1515 scatterMarkDsp.setData(scatterFieldMark);
1516 }
1517
1518 public void updateCurve(SampledSet set) throws VisADException, RemoteException {
1519 last_uSet = new UnionSet(new SampledSet[] {set});
1520 curveDraw.setCurves(last_uSet);
1521 lastCurve.setData(last_uSet);
1522 }
1523
1524 public void setOther(ImageCurveSelector other) {
1525 this.other = other;
1526 }
1527
1528 @Override public void doAction()
1529 throws VisADException, RemoteException {
1530 if (!init) {
1531 init = true;
1532 return;
1533 }
1534 }
1535
1536 public void setVisible(boolean visible) throws VisADException, RemoteException {
1537 curveDraw.setVisible(visible);
1538 }
1539
1540 }
1541
1542 private class ImageBoxSelector extends CellImpl {
1543 boolean init = false;
1544 boolean active = true;
1545 SubsetRubberBandBox subsetBox;
1546 Set imageDomain;
1547 int domainLen_0;
1548 LineDrawing lastBox;
1549 ImageBoxSelector other;
1550 float maskVal;
1551 boolean earthCoordDomain = false;
1552 MyStatsTable myTable = null;
1553 int myTableIndex = 0;
1554
1555 ImageBoxSelector(SubsetRubberBandBox subsetBox, Set imageDomain, DisplayMaster master, Color color, float maskVal, MyStatsTable mst)
1556 throws VisADException, RemoteException {
1557 super();
1558 this.myTable = mst;
1559 myTableIndex = 0;
1560 if (color == Color.magenta) myTableIndex = 1;
1561 if (color == Color.green) myTableIndex = 2;
1562 if (color == Color.blue) myTableIndex = 3;
1563 this.subsetBox = subsetBox;
1564 this.imageDomain = imageDomain;
1565 int[] lens = ((Gridded2DSet)imageDomain).getLengths();
1566 this.maskVal = maskVal;
1567 domainLen_0 = lens[0];
1568 lastBox = new LineDrawing("last_box");
1569 lastBox.setColor(color);
1570 master.addDisplayable(lastBox);
1571 subsetBox.addAction(this);
1572 master.addDisplayable(subsetBox);
1573 RealTupleType rtt = ((SetType)imageDomain.getType()).getDomain();
1574 if (rtt.equals(RealTupleType.SpatialEarth2DTuple) ||
1575 rtt.equals(RealTupleType.LatitudeLongitudeTuple)) {
1576 earthCoordDomain = true;
1577 }
1578 }
1579
1580 @Override public void doAction()
1581 throws VisADException, RemoteException
1582 {
1583 if (!init) {
1584 init = true;
1585 return;
1586 }
1587
1588 if (!active) {
1589 return;
1590 }
1591
1592 Gridded2DSet set = subsetBox.getBounds();
1593 float[][] corners = set.getSamples(false);
1594 float[][] coords = corners;
1595
1596 if ((imageDomain instanceof Linear2DSet) || !earthCoordDomain) {
1597 coords = ((Gridded2DSet)imageDomain).valueToGrid(corners);
1598 }
1599
1600 float[] coords_0 = coords[0];
1601 float[] coords_1 = coords[1];
1602
1603 int low_0 = Math.round(Math.min(coords_0[0], coords_0[1]));
1604 int low_1 = Math.round(Math.min(coords_1[0], coords_1[1]));
1605 int hi_0 = Math.round(Math.max(coords_0[0], coords_0[1]));
1606 int hi_1 = Math.round(Math.max(coords_1[0], coords_1[1]));
1607
1608 int len_0 = (hi_0 - low_0) + 1;
1609 int len_1 = (hi_1 - low_1) + 1;
1610 int len = len_0*len_1;
1611
1612 float[][] markScatter = new float[3][len];
1613 int[] selected = new int[len];
1614
1615 for (int j=0; j<len_1; j++) {
1616 for (int i=0; i<len_0; i++) {
1617 int idx = (j+low_1)*domainLen_0 + (i+low_0);
1618 int k = j*len_0 + i;
1619 markScatter[0][k] = scatterFieldRange[0][idx];
1620 markScatter[1][k] = scatterFieldRange[1][idx];
1621 markScatter[2][k] = maskVal;
1622 selected[k] = idx;
1623 }
1624 }
1625
1626 int last_len = 0;
1627 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false);
1628 float[][] tmp = new float[3][lastMark[0].length];
1629 for (int k=0; k<lastMark[0].length; k++) {
1630 if (lastMark[2][k] != maskVal) {
1631 tmp[0][last_len] = lastMark[0][k];
1632 tmp[1][last_len] = lastMark[1][k];
1633 tmp[2][last_len] = lastMark[2][k];
1634 last_len++;
1635 }
1636 }
1637
1638 float[][] newMarkScatter = new float[3][len+last_len];
1639 System.arraycopy(tmp[0], 0, newMarkScatter[0], 0, last_len);
1640 System.arraycopy(tmp[1], 0, newMarkScatter[1], 0, last_len);
1641 System.arraycopy(tmp[2], 0, newMarkScatter[2], 0, last_len);
1642 System.arraycopy(markScatter[0], 0, newMarkScatter[0], last_len, len);
1643 System.arraycopy(markScatter[1], 0, newMarkScatter[1], last_len, len);
1644 System.arraycopy(markScatter[2], 0, newMarkScatter[2], last_len, len);
1645
1646 Integer1DSet dset = new Integer1DSet(len+last_len);
1647 FlatField scatterFieldMark = new FlatField(
1648 new FunctionType(RealType.Generic,
1649 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset);
1650
1651 scatterFieldMark.setSamples(newMarkScatter, false);
1652 scatterMarkDsp.setData(scatterFieldMark);
1653
1654 if (myTable != null) {
1655 total_area = JPythonMethods.computeSum(Area_field, selected);
1656 myTable.setPoints(markScatter, len, myTableIndex);
1657 }
1658
1659 updateBox();
1660 }
1661
1662 public void setActive(boolean active) {
1663 this.active = active;
1664 }
1665
1666 public void setVisible(boolean visible) throws VisADException, RemoteException {
1667 subsetBox.setVisible(visible);
1668 if (visible) {
1669 lastBox.setVisible(visible);
1670 }
1671 }
1672
1673 public void reset() throws VisADException, RemoteException {
1674 Gridded2DSet set2D =
1675 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple,
1676 new float[][] {{0},{0}}, 1);
1677 lastBox.setVisible(false);
1678 lastBox.setData(set2D);
1679
1680 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false);
1681 float[][] tmp = new float[3][lastMark[0].length];
1682 int cnt = 0;
1683 for (int k=0; k<lastMark[0].length; k++) {
1684 if (lastMark[2][k] != maskVal) {
1685 tmp[0][cnt] = lastMark[0][k];
1686 tmp[1][cnt] = lastMark[1][k];
1687 tmp[2][cnt] = lastMark[2][k];
1688 cnt++;
1689 }
1690 }
1691
1692 FlatField scatterFieldMark;
1693 if (cnt == 2) {
1694 Integer1DSet dset = new Integer1DSet(2);
1695 scatterFieldMark = new FlatField(
1696 new FunctionType(RealType.Generic,
1697 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset);
1698 float[][] markScatter = new float[3][2];
1699 for (int k=0; k<2; k++) {
1700 markScatter[0][k] = scatterFieldRange[0][k];
1701 markScatter[1][k] = scatterFieldRange[1][k];
1702 markScatter[2][k] = 0;
1703 }
1704 scatterFieldMark.setSamples(markScatter, false);
1705 }
1706 else {
1707 Integer1DSet dset = new Integer1DSet(cnt);
1708 scatterFieldMark = new FlatField(
1709 new FunctionType(RealType.Generic,
1710 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset);
1711 float[][] markScatter = new float[3][cnt];
1712 for (int k=0; k<cnt; k++) {
1713 markScatter[0][k] = tmp[0][k];
1714 markScatter[1][k] = tmp[1][k];
1715 markScatter[2][k] = tmp[2][k];
1716 }
1717 scatterFieldMark.setSamples(markScatter, false);
1718 }
1719
1720 scatterMarkDsp.setData(scatterFieldMark);
1721 }
1722
1723 public void setOther(ImageBoxSelector other) {
1724 this.other = other;
1725 }
1726
1727 public void updateBox() throws VisADException, RemoteException {
1728 Gridded3DSet set3D = subsetBox.getLastBox();
1729 float[][] samples = set3D.getSamples(false);
1730 Gridded2DSet set2D =
1731 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple,
1732 new float[][] {samples[0], samples[1]}, samples[0].length);
1733 lastBox.setData(set2D);
1734 other.updateBox(set2D);
1735 }
1736
1737 public void updateBox(Gridded2DSet set2D) throws VisADException, RemoteException {
1738 lastBox.setData(set2D);
1739 }
1740
1741 }
1742
1743 private class ScatterBoxSelector extends CellImpl {
1744 boolean init = false;
1745 double[] x_coords = new double[2];
1746 double[] y_coords = new double[2];
1747 RubberBandBox rbb;
1748 LineDrawing selectBox;
1749 boolean active = true;
1750 float maskVal = 0;
1751
1752 ScatterBoxSelector(DisplayMaster master, Color color, float maskVal) throws VisADException, RemoteException {
1753 selectBox = new LineDrawing("select");
1754 selectBox.setColor(color);
1755
1756 rbb = new RubberBandBox(RealType.XAxis, RealType.YAxis, 1);
1757 rbb.setColor(color);
1758 rbb.addAction(this);
1759
1760 master.addDisplayable(rbb);
1761 master.addDisplayable(selectBox);
1762 this.maskVal = maskVal;
1763 }
1764
1765
1766 @Override public void doAction() throws VisADException, RemoteException {
1767 if (!init) {
1768 init = true;
1769 return;
1770 }
1771
1772 if (!active) {
1773 return;
1774 }
1775
1776 Gridded2DSet set = rbb.getBounds();
1777 float[] low = set.getLow();
1778 float[] hi = set.getHi();
1779 x_coords[0] = low[0];
1780 x_coords[1] = hi[0];
1781 y_coords[0] = low[1];
1782 y_coords[1] = hi[1];
1783
1784 SampledSet[] sets = new SampledSet[4];
1785 sets[0] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{low[0], hi[0]}, {low[1], low[1]}}, 2);
1786 sets[1] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{hi[0], hi[0]}, {low[1], hi[1]}}, 2);
1787 sets[2] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{hi[0], low[0]}, {hi[1], hi[1]}}, 2);
1788 sets[3] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{low[0], low[0]}, {hi[1], low[1]}}, 2);
1789 UnionSet uset = new UnionSet(sets);
1790 selectBox.setData(uset);
1791
1792 try {
1793 histoField.markMaskFieldByRange(x_coords, y_coords, maskVal);
1794 } catch (Exception e) {
1795 e.printStackTrace();
1796 }
1797 }
1798
1799 public void setVisible(boolean visible) throws VisADException, RemoteException {
1800 rbb.setVisible(visible);
1801 if (visible) {
1802 selectBox.setVisible(visible);
1803 }
1804 }
1805
1806 public void setActive(boolean active) {
1807 this.active = active;
1808 }
1809
1810 public void reset() throws Exception {
1811 selectBox.setVisible(false);
1812 selectBox.setData(new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{0f, 0f}, {0f, 0f}}, 2));
1813 histoField.resetMaskField(maskVal);
1814 }
1815 }
1816
1817 private class ScatterCurveSelector extends CellImpl implements DisplayListener {
1818 CurveDrawer curveDraw;
1819 boolean init = false;
1820 UnionSet last_uSet = null;
1821 boolean active = true;
1822 float maskVal = 0;
1823 LineDrawing selectCurve;
1824
1825 ScatterCurveSelector(DisplayMaster master, Color color, float maskVal) throws VisADException, RemoteException {
1826 curveDraw = new CurveDrawer(RealType.XAxis, RealType.YAxis, 1);
1827 curveDraw.setColor(color);
1828 curveDraw.setLineWidth(2);
1829 curveDraw.setData(new UnionSet(new Gridded2DSet[]{
1830 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {
1831 { scatterFieldRange[0][0] }, { scatterFieldRange[1][0]}
1832 }, 1) }));
1833
1834 selectCurve = new LineDrawing("select");
1835 selectCurve.setColor(color);
1836 selectCurve.setLineWidth(2);
1837 master.addDisplayable(curveDraw);
1838 master.addDisplayable(selectCurve);
1839 this.maskVal = maskVal;
1840
1841 curveDraw.addAction(this);
1842 master.addDisplayListener(this);
1843 }
1844
1845 @Override public void displayChanged(DisplayEvent de)
1846 throws VisADException, RemoteException {
1847 if ((de.getId() == DisplayEvent.MOUSE_RELEASED) && (active)) {
1848 UnionSet uSet = curveDraw.getCurves();
1849 if (uSet == last_uSet) return;
1850 SampledSet[] sets = uSet.getSets();
1851 int s_idx = sets.length-1;
1852 float[][] crv;
1853
1854 crv = sets[s_idx].getSamples();
1855 last_uSet = new UnionSet(new SampledSet[] {sets[s_idx]});
1856 curveDraw.setCurves(last_uSet);
1857 selectCurve.setData(last_uSet);
1858
1859 try {
1860 histoField.clearMaskField(maskVal);
1861 histoField.markMaskFieldByCurve(crv, maskVal);
1862 } catch (Exception e) {
1863 e.printStackTrace();
1864 }
1865 }
1866 }
1867
1868 @Override public void doAction() throws VisADException, RemoteException {
1869 if (!init) {
1870 init = true;
1871 return;
1872 }
1873 }
1874
1875 public void setVisible(boolean visible) throws VisADException, RemoteException {
1876 curveDraw.setVisible(visible);
1877 }
1878
1879 public void setActive(boolean active) {
1880 this.active = active;
1881 }
1882
1883 public void reset() throws Exception {
1884 curveDraw.setData(new UnionSet(new Gridded2DSet[]{
1885 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {
1886 { scatterFieldRange[0][0] }, { scatterFieldRange[1][0]}
1887 }, 1) }));
1888 selectCurve.setData(new UnionSet(new Gridded2DSet[]{
1889 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {
1890 { scatterFieldRange[0][0] }, { scatterFieldRange[1][0]}
1891 }, 1) }));
1892 histoField.resetMaskField(maskVal);
1893 }
1894 }
1895
1896 private class BoxCurveSwitch implements ActionListener {
1897
1898 public BoxCurveSwitch() {
1899 }
1900
1901 @Override public void actionPerformed(ActionEvent ae) {
1902 String cmd = ae.getActionCommand();
1903 try {
1904 if (cmd.equals("Box")) {
1905 selectByCurve = false;
1906 } else if (cmd.equals("Curve")) {
1907 selectByCurve = true;
1908 }
1909 }
1910 catch (Exception e) {
1911 e.printStackTrace();
1912 }
1913 }
1914 }
1915
1916 public static float[] minmax(float[] values) {
1917 float min = Float.MAX_VALUE;
1918 float max = -Float.MAX_VALUE;
1919 for (int k = 0; k < values.length; k++) {
1920 float val = values[k];
1921 if ((val == val) && (val < Float.POSITIVE_INFINITY) && (val > Float.NEGATIVE_INFINITY)) {
1922 if (val < min) min = val;
1923 if (val > max) max = val;
1924 }
1925 }
1926 return new float[] {min, max};
1927 }
1928
1929 public boolean getIsLatLon(FlatField field) throws VisADException, RemoteException {
1930 boolean isLL = false;
1931 FunctionType fnc_type = (FunctionType) field.getType();
1932 RealTupleType rtt = fnc_type.getDomain();
1933 if (rtt.equals(RealTupleType.LatitudeLongitudeTuple)) {
1934 isLL = true;
1935 }
1936 else if (!rtt.equals(RealTupleType.SpatialEarth2DTuple)) {
1937 rtt = fnc_type.getDomain().getCoordinateSystem().getReference();
1938 if ( rtt.equals(RealTupleType.LatitudeLongitudeTuple)) {
1939 isLL = true;
1940 }
1941 }
1942 return isLL;
1943 }
1944 }