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