001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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 JButton reset = new JButton("Reset Selections"); 759 reset.addActionListener(e -> resetAllScatterSelectors()); 760 761 buttonPanel.add(reset); 762 buttonPanel.add(computeStatsButton); 763 buttonPanel.add(new JLabel("Background Color:")); 764 buttonPanel.add(bgColorBlack); 765 buttonPanel.add(bgColorWhite); 766 767 //-container = pane; 768 JPanel new_pane = new JPanel(new BorderLayout()); 769 new_pane.add(pane, BorderLayout.CENTER); 770 new_pane.add(buttonPanel, BorderLayout.SOUTH); 771 container = new_pane; 772 return container; 773 } 774 775 /** 776 * Reset the state of all scatter display selections. 777 */ 778 public void resetAllScatterSelectors() { 779 for (int i = 0; i < n_selectors; i++) { 780 resetScatterSelector(i); 781 } 782 } 783 784 /** 785 * Reset the state of a specific scatter display selection. 786 * 787 * @param idx Index of the scatter display selection within {@link #n_selectors}. 788 */ 789 public void resetScatterSelector(int idx) { 790 try { 791 if (statsTable != null) { 792 statsTable.resetValues(idx); 793 } 794 795 ScatterBoxSelector boxSel = scatterBoxSelectors.get(idx); 796 ImageBoxSelector imageXbox = imageXBoxSelectors.get(idx); 797 ImageBoxSelector imageYbox = imageYBoxSelectors.get(idx); 798 ScatterCurveSelector curveSel = scatterCurveSelectors.get(idx); 799 ImageCurveSelector imageXcurve = imageXCurveSelectors.get(idx); 800 ImageCurveSelector imageYcurve = imageYCurveSelectors.get(idx); 801 802 boxSel.reset(); 803 boxSel.setActive(false); 804 boxSel.setVisible(false); 805 806 imageXbox.reset(); 807 imageXbox.setActive(false); 808 imageXbox.setVisible(false); 809 810 imageYbox.reset(); 811 imageYbox.setActive(false); 812 imageYbox.setVisible(false); 813 814 curveSel.reset(); 815 curveSel.setActive(false); 816 curveSel.setVisible(false); 817 818 imageXcurve.reset(); 819 imageXcurve.setActive(false); 820 imageXcurve.setVisible(false); 821 imageYcurve.reset(); 822 imageYcurve.setActive(false); 823 imageYcurve.setVisible(false); 824 } catch (Exception e) { 825 logger.error("Problem resetting selector at index " + idx, e); 826 } 827 } 828 829 public void setBlackBackground(boolean value) { 830 blackBackground = value; 831 } 832 833 public boolean getBlackBackground() { 834 return blackBackground; 835 } 836 837 protected Component getScatterTabComponent() { 838 try { 839 scatterMaster = new XYDisplay("Scatter", RealType.XAxis, RealType.YAxis); 840 } catch (Exception e) { 841 logger.error("Problem creating XYDisplay", e); 842 } 843 return scatterMaster.getComponent(); 844 } 845 846 public DisplayMaster makeImageDisplay(MapProjection mapProj, FlatField image, 847 FlatField mask_image, Range imageRange, ColorTable colorTable) 848 throws VisADException, RemoteException { 849 MapProjectionDisplayJ3D mapProjDsp; 850 DisplayMaster dspMaster; 851 852 mapProjDsp = new MapProjectionDisplayJ3D(MapProjectionDisplay.MODE_2Din3D); 853 mapProjDsp.enableRubberBanding(false); 854 dspMaster = mapProjDsp; 855 mapProjDsp.setMapProjection(mapProj); 856 857 RealType imageRangeType = 858 (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0]; 859 860 boolean alphaflag = false; 861 HydraRGBDisplayable imageDsp = new HydraRGBDisplayable("image", imageRangeType, null, alphaflag, null); 862 863 imageDsp.setData(image); 864 dspMaster.addDisplayable(imageDsp); 865 addMapDisplayables(mapProjDsp); 866 867 if (mask_image != null) { 868 RGBDisplayable maskDsp = 869 new ScatterDisplayable("mask", RealType.Generic, maskColorPalette, false); 870 maskDsp.setData(mask_image); 871 maskDsp.setRangeForColor(0, n_selectors-1); 872 dspMaster.addDisplayable(maskDsp); 873 } 874 875 dspMaster.draw(); 876 877 ScalarMap colorMap = imageDsp.getColorMap(); 878 colorMap.setRange(imageRange.getMin(), imageRange.getMax()); 879 BaseColorControl clrCntrl = (BaseColorControl) colorMap.getControl(); 880 float[][] ct = colorTable.getColorTable(); 881 882 if ( !(alphaflag) && (ct.length == 4) ) { 883 float[][] new_ct = new float[3][]; 884 new_ct[0] = ct[0]; 885 new_ct[1] = ct[1]; 886 new_ct[2] = ct[2]; 887 ct = new_ct; 888 } 889 890 clrCntrl.setTable(ct); 891 892 return dspMaster; 893 } 894 895 public Range getImageRange(FlatField image) 896 throws VisADException, RemoteException { 897 DisplayConventions dc = getDisplayConventions(); 898 Range[] range = GridUtil.fieldMinMax(image); 899 Range imageRange = range[0]; 900 RealType imageRangeType = 901 (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0]; 902 String canonicalName = DataAlias.aliasToCanonical(imageRangeType.getName()); 903 Range dfltRange = dc.getParamRange(canonicalName, null); 904 905 if (dfltRange == null) { 906 imageRange = range[0]; 907 } 908 else if ((imageRange.getMax() - imageRange.getMin()) < (dfltRange.getMax() - dfltRange.getMin())) { 909 } 910 else { 911 imageRange = dfltRange; 912 } 913 return imageRange; 914 } 915 916 public ColorTable getColorTable(FlatField image) 917 throws VisADException, RemoteException { 918 RealType imageRangeType = 919 (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0]; 920 DisplayConventions dc = getDisplayConventions(); 921 return dc.getParamColorTable(imageRangeType.getName()); 922 } 923 924 925 public MapProjection getDataProjection(FlatField image) 926 throws VisADException, RemoteException { 927 MapProjection mp = null; 928 //- get MapProjection from incoming image. If none, use default method 929 FunctionType fnc_type = (FunctionType) image.getType(); 930 RealTupleType rtt = fnc_type.getDomain(); 931 CoordinateSystem cs = rtt.getCoordinateSystem(); 932 Set domainSet = image.getDomainSet(); 933 934 if (cs instanceof visad.CachingCoordinateSystem) { 935 cs = ((visad.CachingCoordinateSystem)cs).getCachedCoordinateSystem(); 936 } 937 938 if (cs instanceof MapProjection) { 939 return (MapProjection) cs; 940 } 941 else if (cs instanceof LongitudeLatitudeCoordinateSystem) { 942 Rectangle2D rect = MultiSpectralData.getLonLatBoundingBox(image); 943 try { 944 mp = new LambertAEA(rect); 945 } catch (Exception e) { 946 System.out.println(" getDataProjection"+e); 947 } 948 return mp; 949 } 950 951 float minLon = Float.NaN; 952 float minLat = Float.NaN; 953 float delLon = Float.NaN; 954 float delLat = Float.NaN; 955 956 if (domainSet instanceof LinearLatLonSet) { 957 MathType type0 = ((SetType)domainSet.getType()).getDomain().getComponent(0); 958 int latI = RealType.Latitude.equals(type0) ? 0 : 1; 959 int lonI = (latI == 1) ? 0 : 1; 960 961 float[] min = ((LinearLatLonSet)domainSet).getLow(); 962 float[] max = ((LinearLatLonSet)domainSet).getHi(); 963 minLon = min[lonI]; 964 minLat = min[latI]; 965 delLon = max[lonI] - min[lonI]; 966 delLat = max[latI] - min[latI]; 967 968 try { 969 mp = new TrivialMapProjection(RealTupleType.SpatialEarth2DTuple, 970 new Rectangle2D.Float(minLon, minLat, delLon, delLat)); 971 } catch (Exception e) { 972 logException("MultiSpectralControl.getDataProjection", e); 973 } 974 975 return mp; 976 } 977 else if (domainSet instanceof Gridded2DSet) { 978 rtt = ((SetType)domainSet.getType()).getDomain(); 979 rtt = RealTupleType.SpatialEarth2DTuple; 980 if (!(rtt.equals(RealTupleType.SpatialEarth2DTuple) || rtt.equals(RealTupleType.LatitudeLongitudeTuple))) { 981 minLon = -180f; 982 minLat = -90f; 983 delLon = 360f; 984 delLat = 180f; 985 } 986 else { 987 int latI = rtt.equals(RealTupleType.SpatialEarth2DTuple) ? 1 : 0; 988 int lonI = (latI == 1) ? 0 : 1; 989 990 float[] min = ((Gridded2DSet)domainSet).getLow(); 991 float[] max = ((Gridded2DSet)domainSet).getHi(); 992 minLon = min[lonI]; 993 minLat = min[latI]; 994 delLon = max[lonI] - min[lonI]; 995 delLat = max[latI] - min[latI]; 996 } 997 } 998 999 try { 1000 mp = new TrivialMapProjection(RealTupleType.SpatialEarth2DTuple, 1001 new Rectangle2D.Float(minLon, minLat, delLon, delLat)); 1002 } catch (Exception e) { 1003 logException("MultiSpectralControl.getDataProjection", e); 1004 } 1005 1006 return mp; 1007 } 1008 1009 public void addMapDisplayables(MapProjectionDisplayJ3D mapProjDsp) 1010 throws VisADException, RemoteException { 1011 MapLines mapLines = new MapLines("maplines"); 1012 URL mapSource = 1013 mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPU"); 1014 try { 1015 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource); 1016 mapLines.setMapLines(mapAdapter.getData()); 1017 mapLines.setColor(java.awt.Color.cyan); 1018 mapProjDsp.addDisplayable(mapLines); 1019 } catch (Exception excp) { 1020 System.out.println("Can't open map file " + mapSource); 1021 System.out.println(excp); 1022 } 1023 1024 mapLines = new MapLines("maplines"); 1025 mapSource = 1026 mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPW"); 1027 try { 1028 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource); 1029 mapLines.setMapLines(mapAdapter.getData()); 1030 mapLines.setColor(java.awt.Color.cyan); 1031 mapProjDsp.addDisplayable(mapLines); 1032 } catch (Exception excp) { 1033 System.out.println("Can't open map file " + mapSource); 1034 System.out.println(excp); 1035 } 1036 1037 mapLines = new MapLines("maplines"); 1038 mapSource = 1039 mapProjDsp.getClass().getResource("/auxdata/maps/OUTLHPOL"); 1040 try { 1041 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource); 1042 mapLines.setMapLines(mapAdapter.getData()); 1043 mapLines.setColor(java.awt.Color.cyan); 1044 mapProjDsp.addDisplayable(mapLines); 1045 } catch (Exception excp) { 1046 System.out.println("Can't open map file " + mapSource); 1047 System.out.println(excp); 1048 } 1049 } 1050 1051 public boolean getSelectByCurve() { 1052 return selectByCurve; 1053 } 1054 1055 private FlatField resample(FlatField X_field, FlatField Y_field) throws VisADException, RemoteException { 1056 1057 RealTupleType X_domainRef = null; 1058 RealTupleType Y_domainRef = null; 1059 float[][] coords = null; 1060 int[] indexes = null; 1061 float[][] Yvalues = Y_field.getFloats(false); 1062 float[][] Xsamples = ((SampledSet)X_field.getDomainSet()).getSamples(false); 1063 1064 CoordinateSystem X_cs = X_field.getDomainCoordinateSystem(); 1065 if (X_cs == null) { 1066 RealTupleType X_domain = ((FunctionType)X_field.getType()).getDomain(); 1067 } 1068 else { 1069 X_domainRef = X_cs.getReference(); 1070 } 1071 1072 CoordinateSystem Y_cs = Y_field.getDomainCoordinateSystem(); 1073 if (Y_cs == null) { 1074 RealTupleType Y_domain = ((FunctionType)Y_field.getType()).getDomain(); 1075 } 1076 else { 1077 Y_domainRef = Y_cs.getReference(); 1078 } 1079 1080 if ( X_domainRef != null && Y_domainRef != null) { 1081 Xsamples = X_cs.toReference(Xsamples); 1082 coords = Y_cs.fromReference(Xsamples); 1083 indexes = ((SampledSet)Y_field.getDomainSet()).valueToIndex(coords); 1084 } 1085 else if ( X_domainRef == null && Y_domainRef != null ) { 1086 Xsamples = Y_cs.fromReference(Xsamples); 1087 indexes = ((SampledSet)Y_field.getDomainSet()).valueToIndex(Xsamples); 1088 } 1089 else if ( X_domainRef != null && Y_domainRef == null) { 1090 Xsamples = X_cs.toReference(Xsamples); 1091 Gridded2DSet domSet = (Gridded2DSet) Y_field.getDomainSet(); 1092 1093 // TODO this is a hack for the longitude range problem 1094 float[] hi = domSet.getHi(); 1095 if (hi[0] <= 180f) { 1096 for (int t=0; t<Xsamples[0].length; t++) { 1097 if (Xsamples[0][t] > 180f) Xsamples[0][t] -=360; 1098 } 1099 } 1100 1101 indexes = ((SampledSet)Y_field.getDomainSet()).valueToIndex(Xsamples); 1102 } 1103 else if (X_domainRef == null && Y_domainRef == null) { 1104 Gridded2DSet domSet = (Gridded2DSet) Y_field.getDomainSet(); 1105 indexes = domSet.valueToIndex(Xsamples); 1106 } 1107 1108 float[][] new_values = new float[1][indexes.length]; 1109 for (int k=0; k<indexes.length; k++) { 1110 new_values[0][k] = Float.NaN; 1111 if (indexes[k] >= 0) { 1112 new_values[0][k] = Yvalues[0][indexes[k]]; 1113 } 1114 } 1115 1116 FunctionType ftype = new FunctionType(((FunctionType)X_field.getType()).getDomain(), 1117 ((FunctionType)Y_field.getType()).getRange()); 1118 Y_field = new FlatField(ftype, X_field.getDomainSet()); 1119 Y_field.setSamples(new_values); 1120 1121 return Y_field; 1122 } 1123 1124 1125 private class ScatterDisplayable extends RGBDisplayable { 1126 ScatterDisplayable(String name, RealType rgbRealType, float[][] colorPalette, boolean alphaflag) 1127 throws VisADException, RemoteException { 1128 super(name, rgbRealType, colorPalette, alphaflag); 1129 } 1130 } 1131 1132 private class ImageControl extends DisplayControlImpl { 1133 HydraRGBDisplayable rgbDisp; 1134 DisplayConventions dc; 1135 ColorTableWidget ctw; 1136 1137 ImageControl(HydraRGBDisplayable rgbDisp, DisplayConventions dc) { 1138 super(); 1139 this.rgbDisp = rgbDisp; 1140 this.dc = dc; 1141 } 1142 1143 @Override public void setRange(Range r) throws VisADException, RemoteException { 1144 if (r != null) { 1145 rgbDisp.setRangeForColor(r.getMin(), r.getMax()); 1146 } 1147 } 1148 1149 @Override public DisplayConventions getDisplayConventions() { 1150 return dc; 1151 } 1152 1153 @Override public void setColorTable(ColorTable ct) { 1154 try { 1155 ctw.setColorTable(ct); 1156 ScalarMap colorMap = rgbDisp.getColorMap(); 1157 BaseColorControl clrCntrl = (BaseColorControl) colorMap.getControl(); 1158 1159 // Force incoming color dimension to that of the colorMap 1160 // 1161 int numComps = clrCntrl.getNumberOfComponents(); 1162 float[][] clrTable = ct.getColorTable(); 1163 float[][] newTable = null; 1164 if (numComps != clrTable.length) { 1165 if (numComps < clrTable.length) { 1166 newTable = new float[numComps][clrTable[0].length]; 1167 for (int k=0; k<numComps; k++) { 1168 System.arraycopy(clrTable[k], 0, newTable[k], 0, newTable[0].length); 1169 } 1170 } 1171 else if (numComps > clrTable.length) { 1172 newTable = new float[numComps][clrTable[0].length]; 1173 for (int k=0; k<clrTable.length; k++) { 1174 System.arraycopy(clrTable[k], 0, newTable[k], 0, newTable[0].length); 1175 } 1176 newTable[3] = new float[clrTable[0].length]; 1177 } 1178 } else { 1179 newTable = new float[numComps][clrTable[0].length]; 1180 for (int k = 0; k < clrTable.length; k++) { 1181 System.arraycopy(clrTable[k], 0, newTable[k], 0, newTable[0].length); 1182 } 1183 } 1184 clrCntrl.setTable(newTable); 1185 } 1186 catch (Exception e) { 1187 LogUtil.logException("Problem changing color table", e); 1188 } 1189 } 1190 } 1191 1192 private class ImageCurveSelector extends CellImpl implements DisplayListener { 1193 boolean init = false; 1194 CurveDrawer curveDraw; 1195 DisplayMaster dspMaster; 1196 Gridded2DSet domainSet; 1197 CoordinateSystem cs; 1198 int domainLen_0; 1199 int domainLen_1; 1200 ImageCurveSelector other; 1201 UnionSet last_uSet = null; 1202 boolean imageLatLon = false; 1203 boolean active = true; 1204 float maskVal; 1205 LineDrawing lastCurve; 1206 StatsTable myTable = null; 1207 int myTableIndex = 0; 1208 1209 ImageCurveSelector(CurveDrawer curveDraw, FlatField image, DisplayMaster master, Color color, float maskVal, StatsTable mst) 1210 throws VisADException, RemoteException { 1211 this.curveDraw = curveDraw; 1212 this.maskVal = maskVal; 1213 this.myTable = mst; 1214 myTableIndex = 0; 1215 if (color == Color.magenta) myTableIndex = 1; 1216 if (color == Color.green) myTableIndex = 2; 1217 if (color == Color.blue) myTableIndex = 3; 1218 dspMaster = master; 1219 dspMaster.addDisplayListener(this); 1220 domainSet = (Gridded2DSet) image.getDomainSet(); 1221 int[] lens = domainSet.getLengths(); 1222 domainLen_0 = lens[0]; 1223 domainLen_1 = lens[1]; 1224 cs = ((FunctionType)image.getType()).getDomain().getCoordinateSystem(); 1225 RealTupleType reference = null; 1226 if (cs != null) { 1227 reference = cs.getReference(); 1228 } 1229 else { 1230 reference = ((SetType)domainSet.getType()).getDomain(); 1231 } 1232 RealType[] rtypes = reference.getRealComponents(); 1233 if (rtypes[0].equals(RealType.Latitude)) imageLatLon = true; 1234 lastCurve = new LineDrawing("lastCurve"); 1235 lastCurve.setColor(color); 1236 lastCurve.setLineWidth(2); 1237 master.addDisplayable(lastCurve); 1238 } 1239 1240 @Override public void displayChanged(DisplayEvent de) 1241 throws VisADException, RemoteException { 1242 if ((de.getId() == DisplayEvent.MOUSE_RELEASED) && (active)) { 1243 UnionSet uSet = curveDraw.getCurves(); 1244 if (uSet == last_uSet) return; 1245 SampledSet[] sets = uSet.getSets(); 1246 int s_idx = sets.length-1; 1247 float[][] crv; 1248 1249 if (cs != null) { 1250 crv = sets[s_idx].getSamples(); 1251 if (imageLatLon) { 1252 float[] tmp = crv[0]; 1253 crv[0] = crv[1]; 1254 crv[1] = tmp; 1255 } 1256 crv = cs.fromReference(crv); 1257 crv = domainSet.valueToGrid(crv); 1258 } 1259 else { 1260 crv = sets[s_idx].getSamples(); 1261 crv = domainSet.valueToGrid(crv); 1262 } 1263 1264 float[][] onImage = new float[2][crv[0].length]; 1265 int cnt = 0; 1266 for (int i=0; i<crv[0].length; i++) { 1267 if ( ((crv[0][i] >= 0)&&(crv[0][i] <= domainLen_0)) && 1268 ((crv[1][i] >= 0)&&(crv[1][i] <= domainLen_1)) ) { 1269 onImage[0][cnt] = crv[0][i]; 1270 onImage[1][cnt] = crv[1][i]; 1271 cnt++; 1272 } 1273 } 1274 uSet = new UnionSet(new SampledSet[] {sets[s_idx]}); 1275 last_uSet = uSet; 1276 lastCurve.setData(last_uSet); 1277 curveDraw.setCurves(uSet); 1278 other.updateCurve(sets[s_idx]); 1279 1280 if (cnt == 0) { 1281 return; 1282 } 1283 1284 float[][] tmp = new float[2][cnt]; 1285 System.arraycopy(onImage[0], 0, tmp[0], 0, cnt); 1286 System.arraycopy(onImage[1], 0, tmp[1], 0, cnt); 1287 onImage = tmp; 1288 1289 float[] minmaxvals = minmax(onImage[0]); 1290 int low_0 = Math.round(minmaxvals[0]); 1291 int hi_0 = Math.round(minmaxvals[1]); 1292 minmaxvals = minmax(onImage[1]); 1293 int low_1 = Math.round(minmaxvals[0]); 1294 int hi_1 = Math.round(minmaxvals[1]); 1295 1296 int len_0 = (hi_0 - low_0) + 1; 1297 int len_1 = (hi_1 - low_1) + 1; 1298 int len = len_0*len_1; 1299 1300 tmp = new float[3][len]; 1301 int[] tmpsel = new int[len]; 1302 1303 int num_inside = 0; 1304 for (int j=0; j<len_1; j++) { 1305 for (int i=0; i<len_0; i++) { 1306 int idx = (j+low_1)*domainLen_0 + (i+low_0); 1307 float x = (float) (i + low_0); 1308 float y = (float) (j + low_1); 1309 if (DelaunayCustom.inside(crv, x, y)) { 1310 tmp[0][num_inside] = scatterFieldRange[0][idx]; 1311 tmp[1][num_inside] = scatterFieldRange[1][idx]; 1312 tmp[2][num_inside] = maskVal; 1313 tmpsel[num_inside] = idx; 1314 num_inside++; 1315 } 1316 } 1317 } 1318 len = num_inside; 1319 float[][] markScatter = new float[3][len]; 1320 System.arraycopy(tmp[0], 0, markScatter[0], 0, len); 1321 System.arraycopy(tmp[1], 0, markScatter[1], 0, len); 1322 System.arraycopy(tmp[2], 0, markScatter[2], 0, len); 1323 1324 1325 int last_len = 0; 1326 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false); 1327 tmp = new float[3][lastMark[0].length]; 1328 for (int k=0; k<lastMark[0].length; k++) { 1329 if (lastMark[2][k] != maskVal) { 1330 tmp[0][last_len] = lastMark[0][k]; 1331 tmp[1][last_len] = lastMark[1][k]; 1332 tmp[2][last_len] = lastMark[2][k]; 1333 last_len++; 1334 } 1335 } 1336 1337 float[][] newMarkScatter = new float[3][len+last_len]; 1338 System.arraycopy(tmp[0], 0, newMarkScatter[0], 0, last_len); 1339 System.arraycopy(tmp[1], 0, newMarkScatter[1], 0, last_len); 1340 System.arraycopy(tmp[2], 0, newMarkScatter[2], 0, last_len); 1341 System.arraycopy(markScatter[0], 0, newMarkScatter[0], last_len, len); 1342 System.arraycopy(markScatter[1], 0, newMarkScatter[1], last_len, len); 1343 System.arraycopy(markScatter[2], 0, newMarkScatter[2], last_len, len); 1344 1345 Integer1DSet dset = new Integer1DSet(len+last_len); 1346 FlatField scatterFieldMark = new FlatField( 1347 new FunctionType(RealType.Generic, 1348 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset); 1349 1350 scatterFieldMark.setSamples(newMarkScatter, false); 1351 scatterMarkDsp.setData(scatterFieldMark); 1352 1353 if (myTable != null) { 1354 int[] selected = new int[len]; 1355 System.arraycopy(tmpsel, 0, selected, 0, len); 1356 total_area = JPythonMethods.computeSum(Area_field, selected); 1357 myTable.setPoints(markScatter, len, myTableIndex, total_area); 1358 } 1359 1360 } 1361 } 1362 1363 public void setActive(boolean active) { 1364 this.active = active; 1365 } 1366 1367 public void reset() throws VisADException, RemoteException { 1368 1369 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false); 1370 float[][] tmp = new float[3][lastMark[0].length]; 1371 int cnt = 0; 1372 for (int k=0; k<lastMark[0].length; k++) { 1373 if (lastMark[2][k] != maskVal) { 1374 tmp[0][cnt] = lastMark[0][k]; 1375 tmp[1][cnt] = lastMark[1][k]; 1376 tmp[2][cnt] = lastMark[2][k]; 1377 cnt++; 1378 } 1379 } 1380 1381 RealTupleType type = ((SetType)curveDraw.getCurves().getType()).getDomain(); 1382 curveDraw.setCurves(new UnionSet(new Gridded2DSet[]{ 1383 new Gridded2DSet(type, new float[][] { 1384 { 0.0f }, { 0.0f }}, 1) })); 1385 1386 lastCurve.setData(new UnionSet(new Gridded2DSet[]{ 1387 new Gridded2DSet(type, new float[][] { 1388 { 0.0f }, { 0.0f }}, 1) })); 1389 1390 FlatField scatterFieldMark = null; 1391 if (cnt == 0) { 1392 Integer1DSet dset = new Integer1DSet(2); 1393 scatterFieldMark = new FlatField( 1394 new FunctionType(RealType.Generic, 1395 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset); 1396 float[][] markScatter = new float[3][2]; 1397 for (int k=0; k<2; k++) { 1398 markScatter[0][k] = scatterFieldRange[0][k]; 1399 markScatter[1][k] = scatterFieldRange[1][k]; 1400 markScatter[2][k] = 0; 1401 } 1402 scatterFieldMark.setSamples(markScatter, false); 1403 } 1404 else { 1405 Integer1DSet dset = new Integer1DSet(cnt); 1406 scatterFieldMark = new FlatField( 1407 new FunctionType(RealType.Generic, 1408 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset); 1409 float[][] markScatter = new float[3][cnt]; 1410 for (int k=0; k<cnt; k++) { 1411 markScatter[0][k] = tmp[0][k]; 1412 markScatter[1][k] = tmp[1][k]; 1413 markScatter[2][k] = tmp[2][k]; 1414 } 1415 scatterFieldMark.setSamples(markScatter, false); 1416 } 1417 1418 scatterMarkDsp.setData(scatterFieldMark); 1419 } 1420 1421 public void updateCurve(SampledSet set) throws VisADException, RemoteException { 1422 last_uSet = new UnionSet(new SampledSet[] {set}); 1423 curveDraw.setCurves(last_uSet); 1424 lastCurve.setData(last_uSet); 1425 } 1426 1427 public void setOther(ImageCurveSelector other) { 1428 this.other = other; 1429 } 1430 1431 @Override public void doAction() 1432 throws VisADException, RemoteException { 1433 if (!init) { 1434 init = true; 1435 return; 1436 } 1437 } 1438 1439 public void setVisible(boolean visible) throws VisADException, RemoteException { 1440 curveDraw.setVisible(visible); 1441 } 1442 1443 } 1444 1445 private class ImageBoxSelector extends CellImpl { 1446 boolean init = false; 1447 boolean active = true; 1448 SubsetRubberBandBox subsetBox; 1449 Set imageDomain; 1450 int domainLen_0; 1451 LineDrawing lastBox; 1452 ImageBoxSelector other; 1453 float maskVal; 1454 boolean earthCoordDomain = false; 1455 StatsTable myTable = null; 1456 int myTableIndex = 0; 1457 1458 ImageBoxSelector(SubsetRubberBandBox subsetBox, Set imageDomain, DisplayMaster master, Color color, float maskVal, StatsTable mst) 1459 throws VisADException, RemoteException { 1460 super(); 1461 this.myTable = mst; 1462 myTableIndex = 0; 1463 if (color == Color.magenta) myTableIndex = 1; 1464 if (color == Color.green) myTableIndex = 2; 1465 if (color == Color.blue) myTableIndex = 3; 1466 this.subsetBox = subsetBox; 1467 this.imageDomain = imageDomain; 1468 int[] lens = ((Gridded2DSet)imageDomain).getLengths(); 1469 this.maskVal = maskVal; 1470 domainLen_0 = lens[0]; 1471 lastBox = new LineDrawing("last_box"); 1472 lastBox.setColor(color); 1473 master.addDisplayable(lastBox); 1474 subsetBox.addAction(this); 1475 master.addDisplayable(subsetBox); 1476 RealTupleType rtt = ((SetType)imageDomain.getType()).getDomain(); 1477 if (rtt.equals(RealTupleType.SpatialEarth2DTuple) || 1478 rtt.equals(RealTupleType.LatitudeLongitudeTuple)) { 1479 earthCoordDomain = true; 1480 } 1481 } 1482 1483 @Override public void doAction() 1484 throws VisADException, RemoteException 1485 { 1486 if (!init) { 1487 init = true; 1488 return; 1489 } 1490 1491 if (!active) { 1492 return; 1493 } 1494 1495 Gridded2DSet set = subsetBox.getBounds(); 1496 float[][] corners = set.getSamples(false); 1497 float[][] coords = corners; 1498 if (corners == null) return; 1499 1500 if ((imageDomain instanceof Linear2DSet) || !earthCoordDomain) { 1501 coords = ((Gridded2DSet)imageDomain).valueToGrid(corners); 1502 } 1503 1504 float[] coords_0 = coords[0]; 1505 float[] coords_1 = coords[1]; 1506 1507 int low_0 = Math.round(Math.min(coords_0[0], coords_0[1])); 1508 int low_1 = Math.round(Math.min(coords_1[0], coords_1[1])); 1509 int hi_0 = Math.round(Math.max(coords_0[0], coords_0[1])); 1510 int hi_1 = Math.round(Math.max(coords_1[0], coords_1[1])); 1511 1512 int len_0 = (hi_0 - low_0) + 1; 1513 int len_1 = (hi_1 - low_1) + 1; 1514 int len = len_0*len_1; 1515 1516 float[][] markScatter = new float[3][len]; 1517 int[] selected = new int[len]; 1518 1519 for (int j=0; j<len_1; j++) { 1520 for (int i=0; i<len_0; i++) { 1521 int idx = (j+low_1)*domainLen_0 + (i+low_0); 1522 int k = j*len_0 + i; 1523 markScatter[0][k] = scatterFieldRange[0][idx]; 1524 markScatter[1][k] = scatterFieldRange[1][idx]; 1525 markScatter[2][k] = maskVal; 1526 selected[k] = idx; 1527 } 1528 } 1529 1530 int last_len = 0; 1531 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false); 1532 float[][] tmp = new float[3][lastMark[0].length]; 1533 for (int k=0; k<lastMark[0].length; k++) { 1534 if (lastMark[2][k] != maskVal) { 1535 tmp[0][last_len] = lastMark[0][k]; 1536 tmp[1][last_len] = lastMark[1][k]; 1537 tmp[2][last_len] = lastMark[2][k]; 1538 last_len++; 1539 } 1540 } 1541 1542 float[][] newMarkScatter = new float[3][len+last_len]; 1543 System.arraycopy(tmp[0], 0, newMarkScatter[0], 0, last_len); 1544 System.arraycopy(tmp[1], 0, newMarkScatter[1], 0, last_len); 1545 System.arraycopy(tmp[2], 0, newMarkScatter[2], 0, last_len); 1546 System.arraycopy(markScatter[0], 0, newMarkScatter[0], last_len, len); 1547 System.arraycopy(markScatter[1], 0, newMarkScatter[1], last_len, len); 1548 System.arraycopy(markScatter[2], 0, newMarkScatter[2], last_len, len); 1549 1550 Integer1DSet dset = new Integer1DSet(len+last_len); 1551 FlatField scatterFieldMark = new FlatField( 1552 new FunctionType(RealType.Generic, 1553 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset); 1554 1555 scatterFieldMark.setSamples(newMarkScatter, false); 1556 scatterMarkDsp.setData(scatterFieldMark); 1557 1558 if (myTable != null) { 1559 total_area = JPythonMethods.computeSum(Area_field, selected); 1560 myTable.setPoints(markScatter, len, myTableIndex, total_area); 1561 } 1562 1563 updateBox(); 1564 } 1565 1566 public void setActive(boolean active) { 1567 this.active = active; 1568 } 1569 1570 public void setVisible(boolean visible) throws VisADException, RemoteException { 1571 subsetBox.setVisible(visible); 1572 if (visible) { 1573 lastBox.setVisible(visible); 1574 } 1575 } 1576 1577 public void reset() throws VisADException, RemoteException { 1578 Gridded2DSet set2D = 1579 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, 1580 new float[][] {{0},{0}}, 1); 1581 lastBox.setVisible(false); 1582 lastBox.setData(set2D); 1583 1584 float[][] lastMark = ((FlatField)scatterMarkDsp.getData()).getFloats(false); 1585 float[][] tmp = new float[3][lastMark[0].length]; 1586 int cnt = 0; 1587 for (int k=0; k<lastMark[0].length; k++) { 1588 if (lastMark[2][k] != maskVal) { 1589 tmp[0][cnt] = lastMark[0][k]; 1590 tmp[1][cnt] = lastMark[1][k]; 1591 tmp[2][cnt] = lastMark[2][k]; 1592 cnt++; 1593 } 1594 } 1595 1596 FlatField scatterFieldMark; 1597 if (cnt == 2) { 1598 Integer1DSet dset = new Integer1DSet(2); 1599 scatterFieldMark = new FlatField( 1600 new FunctionType(RealType.Generic, 1601 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset); 1602 float[][] markScatter = new float[3][2]; 1603 for (int k=0; k<2; k++) { 1604 markScatter[0][k] = scatterFieldRange[0][k]; 1605 markScatter[1][k] = scatterFieldRange[1][k]; 1606 markScatter[2][k] = 0; 1607 } 1608 scatterFieldMark.setSamples(markScatter, false); 1609 } 1610 else { 1611 Integer1DSet dset = new Integer1DSet(cnt); 1612 scatterFieldMark = new FlatField( 1613 new FunctionType(RealType.Generic, 1614 new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.getRealType("mask"))), dset); 1615 float[][] markScatter = new float[3][cnt]; 1616 for (int k=0; k<cnt; k++) { 1617 markScatter[0][k] = tmp[0][k]; 1618 markScatter[1][k] = tmp[1][k]; 1619 markScatter[2][k] = tmp[2][k]; 1620 } 1621 scatterFieldMark.setSamples(markScatter, false); 1622 } 1623 1624 scatterMarkDsp.setData(scatterFieldMark); 1625 } 1626 1627 public void setOther(ImageBoxSelector other) { 1628 this.other = other; 1629 } 1630 1631 public void updateBox() throws VisADException, RemoteException { 1632 Gridded3DSet set3D = subsetBox.getLastBox(); 1633 float[][] samples = set3D.getSamples(false); 1634 Gridded2DSet set2D = 1635 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, 1636 new float[][] {samples[0], samples[1]}, samples[0].length); 1637 lastBox.setData(set2D); 1638 other.updateBox(set2D); 1639 } 1640 1641 public void updateBox(Gridded2DSet set2D) throws VisADException, RemoteException { 1642 lastBox.setData(set2D); 1643 } 1644 1645 } 1646 1647 private class ScatterBoxSelector extends CellImpl { 1648 boolean init = false; 1649 double[] x_coords = new double[2]; 1650 double[] y_coords = new double[2]; 1651 RubberBandBox rbb; 1652 LineDrawing selectBox; 1653 boolean active = true; 1654 float maskVal = 0; 1655 1656 ScatterBoxSelector(DisplayMaster master, Color color, float maskVal) throws VisADException, RemoteException { 1657 selectBox = new LineDrawing("select"); 1658 selectBox.setColor(color); 1659 1660 rbb = new RubberBandBox(RealType.XAxis, RealType.YAxis, 1); 1661 rbb.setColor(color); 1662 rbb.addAction(this); 1663 1664 master.addDisplayable(rbb); 1665 master.addDisplayable(selectBox); 1666 this.maskVal = maskVal; 1667 } 1668 1669 1670 @Override public void doAction() throws VisADException, RemoteException { 1671 if (!init) { 1672 init = true; 1673 return; 1674 } 1675 1676 if (!active) { 1677 return; 1678 } 1679 1680 Gridded2DSet set = rbb.getBounds(); 1681 float[] low = set.getLow(); 1682 float[] hi = set.getHi(); 1683 x_coords[0] = low[0]; 1684 x_coords[1] = hi[0]; 1685 y_coords[0] = low[1]; 1686 y_coords[1] = hi[1]; 1687 1688 SampledSet[] sets = new SampledSet[4]; 1689 sets[0] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{low[0], hi[0]}, {low[1], low[1]}}, 2); 1690 sets[1] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{hi[0], hi[0]}, {low[1], hi[1]}}, 2); 1691 sets[2] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{hi[0], low[0]}, {hi[1], hi[1]}}, 2); 1692 sets[3] = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{low[0], low[0]}, {hi[1], low[1]}}, 2); 1693 UnionSet uset = new UnionSet(sets); 1694 selectBox.setData(uset); 1695 1696 try { 1697 histoField.markMaskFieldByRange(x_coords, y_coords, maskVal); 1698 } catch (Exception e) { 1699 logger.error("Problem changing histogram", e); 1700 } 1701 } 1702 1703 public void setVisible(boolean visible) throws VisADException, RemoteException { 1704 rbb.setVisible(visible); 1705 if (visible) { 1706 selectBox.setVisible(visible); 1707 } 1708 } 1709 1710 public void setActive(boolean active) { 1711 this.active = active; 1712 } 1713 1714 public void reset() throws Exception { 1715 if (!active) return; 1716 selectBox.setVisible(false); 1717 selectBox.setData(new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] {{0f, 0f}, {0f, 0f}}, 2)); 1718 histoField.resetMaskField(maskVal); 1719 } 1720 } 1721 1722 private class ScatterCurveSelector extends CellImpl implements DisplayListener { 1723 CurveDrawer curveDraw; 1724 boolean init = false; 1725 UnionSet last_uSet = null; 1726 boolean active = true; 1727 float maskVal = 0; 1728 LineDrawing selectCurve; 1729 1730 ScatterCurveSelector(DisplayMaster master, Color color, float maskVal) throws VisADException, RemoteException { 1731 curveDraw = new CurveDrawer(RealType.XAxis, RealType.YAxis, 1); 1732 curveDraw.setColor(color); 1733 curveDraw.setLineWidth(2); 1734 curveDraw.setData(new UnionSet(new Gridded2DSet[]{ 1735 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] { 1736 { scatterFieldRange[0][0] }, { scatterFieldRange[1][0]} 1737 }, 1) })); 1738 1739 selectCurve = new LineDrawing("select"); 1740 selectCurve.setColor(color); 1741 selectCurve.setLineWidth(2); 1742 master.addDisplayable(curveDraw); 1743 master.addDisplayable(selectCurve); 1744 this.maskVal = maskVal; 1745 1746 curveDraw.addAction(this); 1747 master.addDisplayListener(this); 1748 } 1749 1750 @Override public void displayChanged(DisplayEvent de) 1751 throws VisADException, RemoteException { 1752 if ((de.getId() == DisplayEvent.MOUSE_RELEASED) && (active)) { 1753 UnionSet uSet = curveDraw.getCurves(); 1754 if (uSet == last_uSet) return; 1755 SampledSet[] sets = uSet.getSets(); 1756 int s_idx = sets.length-1; 1757 float[][] crv; 1758 1759 crv = sets[s_idx].getSamples(); 1760 last_uSet = new UnionSet(new SampledSet[] {sets[s_idx]}); 1761 curveDraw.setCurves(last_uSet); 1762 selectCurve.setData(last_uSet); 1763 1764 try { 1765 histoField.clearMaskField(maskVal); 1766 histoField.markMaskFieldByCurve(crv, maskVal); 1767 } catch (Exception e) { 1768 logger.error("Problem handling displayChange", e); 1769 } 1770 } 1771 } 1772 1773 @Override public void doAction() throws VisADException, RemoteException { 1774 if (!init) { 1775 init = true; 1776 return; 1777 } 1778 } 1779 1780 public void setVisible(boolean visible) throws VisADException, RemoteException { 1781 curveDraw.setVisible(visible); 1782 } 1783 1784 public void setActive(boolean active) { 1785 this.active = active; 1786 } 1787 1788 public void reset() throws Exception { 1789 if (!active) return; 1790 curveDraw.setData(new UnionSet(new Gridded2DSet[]{ 1791 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] { 1792 { scatterFieldRange[0][0] }, { scatterFieldRange[1][0]} 1793 }, 1) })); 1794 selectCurve.setData(new UnionSet(new Gridded2DSet[]{ 1795 new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple, new float[][] { 1796 { scatterFieldRange[0][0] }, { scatterFieldRange[1][0]} 1797 }, 1) })); 1798 histoField.resetMaskField(maskVal); 1799 } 1800 } 1801 1802 private class BoxCurveSwitch implements ActionListener { 1803 1804 public BoxCurveSwitch() { 1805 } 1806 1807 @Override public void actionPerformed(ActionEvent ae) { 1808 String cmd = ae.getActionCommand(); 1809 try { 1810 if (cmd.equals("Box")) { 1811 selectByCurve = false; 1812 } else if (cmd.equals("Curve")) { 1813 selectByCurve = true; 1814 } 1815 } catch (Exception e) { 1816 logger.error("Problem switching curve type", e); 1817 } 1818 } 1819 } 1820 1821 public static float[] minmax(float[] values) { 1822 float min = Float.MAX_VALUE; 1823 float max = -Float.MAX_VALUE; 1824 for (int k = 0; k < values.length; k++) { 1825 float val = values[k]; 1826 if ((val == val) && (val < Float.POSITIVE_INFINITY) && (val > Float.NEGATIVE_INFINITY)) { 1827 if (val < min) min = val; 1828 if (val > max) max = val; 1829 } 1830 } 1831 return new float[] {min, max}; 1832 } 1833 1834 public boolean getIsLatLon(FlatField field) throws VisADException, RemoteException { 1835 boolean isLL = false; 1836 FunctionType fnc_type = (FunctionType) field.getType(); 1837 RealTupleType rtt = fnc_type.getDomain(); 1838 if (rtt.equals(RealTupleType.LatitudeLongitudeTuple)) { 1839 isLL = true; 1840 } else if (!rtt.equals(RealTupleType.SpatialEarth2DTuple)) { 1841 rtt = fnc_type.getDomain().getCoordinateSystem().getReference(); 1842 if ( rtt.equals(RealTupleType.LatitudeLongitudeTuple)) { 1843 isLL = true; 1844 } 1845 } 1846 return isLL; 1847 } 1848}