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