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