001/* 002 * $Id: MultiSpectralDisplay.java,v 1.36 2011/03/24 16:06:33 davep Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2011 007 * Space Science and Engineering Center (SSEC) 008 * University of Wisconsin - Madison 009 * 1225 W. Dayton Street, Madison, WI 53706, USA 010 * https://www.ssec.wisc.edu/mcidas 011 * 012 * All Rights Reserved 013 * 014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 015 * some McIDAS-V source code is based on IDV and VisAD source code. 016 * 017 * McIDAS-V is free software; you can redistribute it and/or modify 018 * it under the terms of the GNU Lesser Public License as published by 019 * the Free Software Foundation; either version 3 of the License, or 020 * (at your option) any later version. 021 * 022 * McIDAS-V is distributed in the hope that it will be useful, 023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 025 * GNU Lesser Public License for more details. 026 * 027 * You should have received a copy of the GNU Lesser Public License 028 * along with this program. If not, see http://www.gnu.org/licenses. 029 */ 030 031package edu.wisc.ssec.mcidasv.display.hydra; 032 033import java.awt.Color; 034import java.awt.Component; 035import java.awt.event.ActionEvent; 036import java.awt.event.ActionListener; 037import java.rmi.RemoteException; 038import java.util.ArrayList; 039import java.util.Enumeration; 040import java.util.HashMap; 041import java.util.Hashtable; 042import java.util.List; 043import java.util.Map; 044 045import javax.swing.JComboBox; 046 047import visad.CellImpl; 048import visad.ConstantMap; 049import visad.DataReference; 050import visad.DataReferenceImpl; 051import visad.Display; 052import visad.DisplayEvent; 053import visad.DisplayListener; 054import visad.FlatField; 055import visad.FunctionType; 056import visad.Gridded1DSet; 057import visad.Gridded2DSet; 058import visad.LocalDisplay; 059import visad.Real; 060import visad.RealTuple; 061import visad.RealTupleType; 062import visad.RealType; 063import visad.ScalarMap; 064import visad.VisADException; 065import visad.bom.RubberBandBoxRendererJ3D; 066 067import ucar.unidata.data.DirectDataChoice; 068import ucar.unidata.idv.ViewManager; 069import ucar.unidata.util.LogUtil; 070import ucar.visad.display.DisplayableData; 071import ucar.visad.display.XYDisplay; 072 073import edu.wisc.ssec.mcidasv.control.HydraCombo; 074import edu.wisc.ssec.mcidasv.control.HydraControl; 075import edu.wisc.ssec.mcidasv.control.LinearCombo; 076import edu.wisc.ssec.mcidasv.data.HydraDataSource; 077import edu.wisc.ssec.mcidasv.data.hydra.GrabLineRendererJ3D; 078import edu.wisc.ssec.mcidasv.data.hydra.HydraRGBDisplayable; 079import edu.wisc.ssec.mcidasv.data.hydra.MultiDimensionSubset; 080import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralData; 081import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralDataSource; 082import edu.wisc.ssec.mcidasv.data.hydra.NPPDataSource; 083 084public class MultiSpectralDisplay implements DisplayListener { 085 086 private static final String DISP_NAME = "Spectrum"; 087 private static int cnt = 1; 088 089 private DirectDataChoice dataChoice; 090 091 private ViewManager viewManager; 092 093 private float[] initialRangeX; 094 private float[] initialRangeY = { 180f, 320f }; 095 096 private RealType domainType; 097 private RealType rangeType; 098 private RealType uniqueRangeType; 099 100 private ScalarMap xmap; 101 private ScalarMap ymap; 102 103 private LocalDisplay display; 104 105 private FlatField image; 106 107 private FlatField spectrum = null; 108 109 private boolean imageExpired = true; 110 111 private MultiSpectralData data; 112 113 private float waveNumber; 114 115 private List<DataReference> displayedThings = new ArrayList<DataReference>(); 116 private HashMap<String, DataReference> idToRef = new HashMap<String, DataReference>(); 117 private HashMap<DataReference, ConstantMap[]> colorMaps = 118 new HashMap<DataReference, ConstantMap[]>(); 119 120 private HydraControl displayControl; 121 122 private DisplayableData imageDisplay = null; 123 124 private XYDisplay master; 125 126 private Gridded1DSet domainSet; 127 128 private JComboBox bandSelectComboBox = null; 129 130 public MultiSpectralDisplay(final HydraControl control) 131 throws VisADException, RemoteException 132 { 133 displayControl = control; 134 dataChoice = (DirectDataChoice)displayControl.getDataChoice(); 135 136 init(); 137 } 138 139 public MultiSpectralDisplay(final DirectDataChoice dataChoice) 140 throws VisADException, RemoteException 141 { 142 this.dataChoice = dataChoice; 143 init(); 144 } 145 146 // TODO: generalize this so that you can grab the image data for any 147 // channel 148 public FlatField getImageData() { 149 try { 150 if ((imageExpired) || (image == null)) { 151 imageExpired = false; 152 153 MultiDimensionSubset select = null; 154 Hashtable table = dataChoice.getProperties(); 155 Enumeration keys = table.keys(); 156 while (keys.hasMoreElements()) { 157 Object key = keys.nextElement(); 158 if (key instanceof MultiDimensionSubset) { 159 select = (MultiDimensionSubset) table.get(key); 160 } 161 } 162 HashMap subset = select.getSubset(); 163 164 image = data.getImage(waveNumber, subset); 165 image = changeRangeType(image, uniqueRangeType); 166 } 167 } catch (Exception e) { 168 LogUtil.logException("MultiSpectralDisplay.getImageData", e); 169 } 170 171 return image; 172 } 173 174 public FlatField getImageDataFrom(final float channel) { 175 FlatField imageData = null; 176 try { 177 MultiDimensionSubset select = null; 178 Hashtable table = dataChoice.getProperties(); 179 Enumeration keys = table.keys(); 180 while (keys.hasMoreElements()) { 181 Object key = keys.nextElement(); 182 if (key instanceof MultiDimensionSubset) { 183 select = (MultiDimensionSubset) table.get(key); 184 } 185 } 186 HashMap subset = select.getSubset(); 187 imageData = data.getImage(channel, subset); 188 uniqueRangeType = RealType.getRealType(rangeType.getName()+"_"+cnt++); 189 imageData = changeRangeType(imageData, uniqueRangeType); 190 } catch (Exception e) { 191 LogUtil.logException("MultiSpectralDisplay.getImageDataFrom", e); 192 } 193 return imageData; 194 } 195 196 private FlatField changeRangeType(FlatField image, RealType newRangeType) throws VisADException, RemoteException { 197 FunctionType ftype = (FunctionType)image.getType(); 198 FlatField new_image = new FlatField( 199 new FunctionType(ftype.getDomain(), newRangeType), image.getDomainSet()); 200 new_image.setSamples(image.getFloats(false), false); 201 return new_image; 202 } 203 204 205 public LocalDisplay getDisplay() { 206 return display; 207 } 208 209 public Component getDisplayComponent() { 210 return master.getDisplayComponent(); 211 } 212 213 public RealType getDomainType() { 214 return domainType; 215 } 216 217 public RealType getRangeType() { 218 return rangeType; 219 } 220 221 public ViewManager getViewManager() { 222 return viewManager; 223 } 224 225 public MultiSpectralData getMultiSpectralData() { 226 return data; 227 } 228 229 public Gridded1DSet getDomainSet() { 230 return domainSet; 231 } 232 233 private void init() throws VisADException, RemoteException { 234 235 HydraDataSource source = 236 (HydraDataSource) dataChoice.getDataSource(); 237 238 // TODO revisit this, may want to move method up to base class HydraDataSource 239 if (source instanceof NPPDataSource) { 240 data = ((NPPDataSource) source).getMultiSpectralData(dataChoice); 241 } 242 243 if (source instanceof MultiSpectralDataSource) { 244 data = ((MultiSpectralDataSource) source).getMultiSpectralData(dataChoice); 245 } 246 247 waveNumber = data.init_wavenumber; 248 249 try { 250 spectrum = data.getSpectrum(new int[] { 1, 1 }); 251 } catch (Exception e) { 252 LogUtil.logException("MultiSpectralDisplay.init", e); 253 } 254 255 domainSet = (Gridded1DSet)spectrum.getDomainSet(); 256 initialRangeX = getXRange(domainSet); 257 initialRangeY = data.getDataRange(); 258 259 domainType = getDomainType(spectrum); 260 rangeType = getRangeType(spectrum); 261 262 master = new XYDisplay(DISP_NAME, domainType, rangeType); 263 264 setDisplayMasterAttributes(master); 265 266 // set up the x- and y-axis 267 xmap = new ScalarMap(domainType, Display.XAxis); 268 ymap = new ScalarMap(rangeType, Display.YAxis); 269 270 xmap.setRange(initialRangeX[0], initialRangeX[1]); 271 ymap.setRange(initialRangeY[0], initialRangeY[1]); 272 273 display = master.getDisplay(); 274 display.addMap(xmap); 275 display.addMap(ymap); 276 display.addDisplayListener(this); 277 278 new RubberBandBox(this, xmap, ymap); 279 280 if (displayControl == null) { //- add in a ref for the default spectrum, ie no DisplayControl 281 DataReferenceImpl spectrumRef = new DataReferenceImpl(hashCode() + "_spectrumRef"); 282 spectrumRef.setData(spectrum); 283 addRef(spectrumRef, Color.WHITE); 284 } 285 286 if (data.hasBandNames()) { 287 bandSelectComboBox = new JComboBox(data.getBandNames().toArray()); 288 bandSelectComboBox.setSelectedItem(data.init_bandName); 289 bandSelectComboBox.addActionListener(new ActionListener() { 290 public void actionPerformed(ActionEvent e) { 291 String bandName = (String)bandSelectComboBox.getSelectedItem(); 292 if (bandName == null) 293 return; 294 295 HashMap<String, Float> bandMap = data.getBandNameMap(); 296 if (bandMap == null) 297 return; 298 299 if (!bandMap.containsKey(bandName)) 300 return; 301 302 setWaveNumber(bandMap.get(bandName)); 303 } 304 }); 305 } 306 } 307 308 public JComboBox getBandSelectComboBox() { 309 return bandSelectComboBox; 310 } 311 312 // TODO: HACK!! 313 public void setDisplayControl(final HydraControl control) { 314 displayControl = control; 315 } 316 317 public void displayChanged(final DisplayEvent e) throws VisADException, RemoteException { 318 // TODO: write a method like isChannelUpdate(EVENT_ID)? or maybe just 319 // deal with a super long if-statement and put an "OR MOUSE_RELEASED" 320 // up here? 321 if (e.getId() == DisplayEvent.MOUSE_RELEASED_CENTER) { 322 float val = (float)display.getDisplayRenderer().getDirectAxisValue(domainType); 323 setWaveNumber(val); 324 if (displayControl != null) 325 displayControl.handleChannelChange(val); 326 } 327 else if (e.getId() == DisplayEvent.MOUSE_PRESSED_LEFT) { 328 if (e.getInputEvent().isControlDown()) { 329 xmap.setRange(initialRangeX[0], initialRangeX[1]); 330 ymap.setRange(initialRangeY[0], initialRangeY[1]); 331 } 332 } 333 else if (e.getId() == DisplayEvent.MOUSE_RELEASED) { 334 float val = getSelectorValue(channelSelector); 335 if (val != waveNumber) { 336 // TODO: setWaveNumber needs to be rethought, as it calls 337 // setSelectorValue which is redundant in the cases of dragging 338 // or clicking 339 setWaveNumber(val); 340 if (displayControl != null) 341 displayControl.handleChannelChange(val); 342 } 343 } 344 } 345 346 public DisplayableData getImageDisplay() { 347 if (imageDisplay == null) { 348 try { 349 uniqueRangeType = RealType.getRealType(rangeType.getName()+"_"+cnt++); 350 imageDisplay = new HydraRGBDisplayable("image", uniqueRangeType, null, true, displayControl); 351 } catch (Exception e) { 352 LogUtil.logException("MultiSpectralDisplay.getImageDisplay", e); 353 } 354 } 355 return imageDisplay; 356 } 357 358 public float getWaveNumber() { 359 return waveNumber; 360 } 361 362 public int getChannelIndex() throws Exception { 363 return data.getChannelIndexFromWavenumber(waveNumber); 364 } 365 366 public void refreshDisplay() throws VisADException, RemoteException { 367 if (display == null) 368 return; 369 370 synchronized (displayedThings) { 371 for (DataReference ref : displayedThings) { 372 display.removeReference(ref); 373 display.addReference(ref, colorMaps.get(ref)); 374 } 375 } 376 } 377 378 public boolean hasNullData() { 379 try { 380 synchronized (displayedThings) { 381 for (DataReference ref : displayedThings) { 382 if (ref.getData() == null) 383 return true; 384 } 385 } 386 } catch (Exception e) { } 387 return false; 388 } 389 390 /** ID of the selector that controls the displayed channel. */ 391 private final String channelSelector = hashCode() + "_chanSelect"; 392 393 /** The map of selector IDs to selectors. */ 394 private final Map<String, DragLine> selectors = 395 new HashMap<String, DragLine>(); 396 397 public void showChannelSelector() { 398 try { 399 createSelector(channelSelector, Color.GREEN); 400 } catch (Exception e) { 401 LogUtil.logException("MultiSpectralDisplay.showChannelSelector", e); 402 } 403 } 404 405 public void hideChannelSelector() { 406 try { 407 DragLine selector = removeSelector(channelSelector); 408 selector = null; 409 } catch (Exception e) { 410 LogUtil.logException("MultiSpectralDisplay.hideChannelSelector", e); 411 } 412 } 413 414 public DragLine createSelector(final String id, final Color color) throws Exception { 415 if (id == null) 416 throw new NullPointerException("selector id cannot be null"); 417 if (color == null) 418 throw new NullPointerException("selector color cannot be null"); 419 return createSelector(id, makeColorMap(color)); 420 } 421 422 public DragLine createSelector(final String id, final ConstantMap[] color) throws Exception { 423 if (id == null) 424 throw new NullPointerException("selector id cannot be null"); 425 if (color == null) 426 throw new NullPointerException("selector color cannot be null"); 427 428 if (selectors.containsKey(id)) 429 return selectors.get(id); 430 431 DragLine selector = new DragLine(this, id, color, initialRangeY); 432 selector.setSelectedValue(waveNumber); 433 selectors.put(id, selector); 434 return selector; 435 } 436 437 public DragLine getSelector(final String id) { 438 return selectors.get(id); 439 } 440 441 public float getSelectorValue(final String id) { 442 DragLine selector = selectors.get(id); 443 if (selector == null) 444 return Float.NaN; 445 return selector.getSelectedValue(); 446 } 447 448 public void setSelectorValue(final String id, final float value) 449 throws VisADException, RemoteException 450 { 451 DragLine selector = selectors.get(id); 452 if (selector != null) 453 selector.setSelectedValue(value); 454 } 455 456 // BAD BAD BAD BAD 457 public void updateControlSelector(final String id, final float value) { 458 if (displayControl == null) 459 return; 460 if (displayControl instanceof LinearCombo) { 461 ((LinearCombo)displayControl).updateSelector(id, value); 462 } else if (displayControl instanceof HydraCombo) { 463 ((HydraCombo)displayControl).updateComboPanel(id, value); 464 } 465 } 466 467 public DragLine removeSelector(final String id) { 468 DragLine selector = selectors.remove(id); 469 if (selector == null) 470 return null; 471 selector.annihilate(); 472 return selector; 473 } 474 475 public List<DragLine> getSelectors() { 476 return new ArrayList<DragLine>(selectors.values()); 477 } 478 479 /** 480 * @return Whether or not the channel selector is being displayed. 481 */ 482 public boolean displayingChannel() { 483 return (getSelector(channelSelector) != null); 484 } 485 486 public void removeRef(final DataReference thing) throws VisADException, 487 RemoteException 488 { 489 if (display == null) 490 return; 491 492 synchronized (displayedThings) { 493 displayedThings.remove(thing); 494 colorMaps.remove(thing); 495 idToRef.remove(thing.getName()); 496 display.removeReference(thing); 497 } 498 } 499 500 public void addRef(final DataReference thing, final Color color) 501 throws VisADException, RemoteException 502 { 503 if (display == null) 504 return; 505 506 synchronized (displayedThings) { 507 ConstantMap[] colorMap = makeColorMap(color); 508 509 displayedThings.add(thing); 510 idToRef.put(thing.getName(), thing); 511 ConstantMap[] constMaps; 512 if (data.hasBandNames()) { 513 constMaps = new ConstantMap[colorMap.length+2]; 514 System.arraycopy(colorMap, 0, constMaps, 0, colorMap.length); 515 constMaps[colorMap.length] = new ConstantMap(1f, Display.PointMode); 516 constMaps[colorMap.length+1] = new ConstantMap(5f, Display.PointSize); 517 } else { 518 constMaps = colorMap; 519 } 520 colorMaps.put(thing, constMaps); 521 522 display.addReference(thing, constMaps); 523 } 524 } 525 526 public void updateRef(final DataReference thing, final Color color) 527 throws VisADException, RemoteException 528 { 529 ConstantMap[] colorMap = makeColorMap(color); 530 ConstantMap[] constMaps; 531 if (data.hasBandNames()) { 532 constMaps = new ConstantMap[colorMap.length+2]; 533 System.arraycopy(colorMap, 0, constMaps, 0, colorMap.length); 534 constMaps[colorMap.length] = new ConstantMap(1f, Display.PointMode); 535 constMaps[colorMap.length+1] = new ConstantMap(5f, Display.PointSize); 536 } else { 537 constMaps = colorMap; 538 } 539 colorMaps.put(thing, constMaps); 540 idToRef.put(thing.getName(), thing); 541 refreshDisplay(); 542 } 543 544 public void reorderDataRefsById(final List<String> dataRefIds) { 545 if (dataRefIds == null) 546 throw new NullPointerException(""); 547 548 synchronized (displayedThings) { 549 try { 550 displayedThings.clear(); 551 for (String refId : dataRefIds) { 552 DataReference ref = idToRef.get(refId); 553 ConstantMap[] color = colorMaps.get(ref); 554 display.removeReference(ref); 555 display.addReference(ref, color); 556 } 557 } catch (Exception e) { } 558 } 559 } 560 561 // TODO: needs work 562 public boolean setWaveNumber(final float val) { 563 if (data == null) 564 return false; 565 566 if (waveNumber == val) 567 return true; 568 569 try { 570 if (spectrum == null) { 571 spectrum = data.getSpectrum(new int[] { 1, 1 }); 572 } 573 574 Gridded1DSet domain = (Gridded1DSet)spectrum.getDomainSet(); 575 int[] idx = domain.valueToIndex(new float[][] { { val } }); 576 float[][] tmp = domain.indexToValue(idx); 577 float channel = tmp[0][0]; 578 579 setSelectorValue(channelSelector, channel); 580 581 imageExpired = true; 582 } catch (Exception e) { 583 LogUtil.logException("MultiSpectralDisplay.setDisplayedWaveNum", e); 584 return false; 585 } 586 587 waveNumber = val; 588 589 if (data.hasBandNames()) { 590 String name = data.getBandNameFromWaveNumber(waveNumber); 591 bandSelectComboBox.setSelectedItem(name); 592 } 593 594 return true; 595 } 596 597 /** 598 * @return The ConstantMap representation of <code>color</code>. 599 */ 600 public static ConstantMap[] makeColorMap(final Color color) 601 throws VisADException, RemoteException 602 { 603 float r = color.getRed() / 255f; 604 float g = color.getGreen() / 255f; 605 float b = color.getBlue() / 255f; 606 float a = color.getAlpha() / 255f; 607 return new ConstantMap[] { new ConstantMap(r, Display.Red), 608 new ConstantMap(g, Display.Green), 609 new ConstantMap(b, Display.Blue), 610 new ConstantMap(a, Display.Alpha) }; 611 } 612 613 /** 614 * Provides <code>master</code> some sensible default attributes. 615 */ 616 private static void setDisplayMasterAttributes(final XYDisplay master) 617 throws VisADException, RemoteException 618 { 619 master.showAxisScales(true); 620 master.setAspect(2.5, 0.75); 621 622 double[] proj = master.getProjectionMatrix(); 623 proj[0] = 0.35; 624 proj[5] = 0.35; 625 proj[10] = 0.35; 626 627 master.setProjectionMatrix(proj); 628 } 629 630 /** 631 * @return The minimum and maximum values found on the x-axis. 632 */ 633 private static float[] getXRange(final Gridded1DSet domain) { 634 return new float[] { domain.getLow()[0], domain.getHi()[0] }; 635 } 636 637 public static RealType getRangeType(final FlatField spectrum) { 638 return (((FunctionType)spectrum.getType()).getFlatRange().getRealComponents())[0]; 639 } 640 641 private static RealType getDomainType(final FlatField spectrum) { 642 return (((FunctionType)spectrum.getType()).getDomain().getRealComponents())[0]; 643 } 644 645 private static class RubberBandBox extends CellImpl { 646 647 private static final String RBB = "_rubberband"; 648 649 private DataReference rubberBand; 650 651 private boolean init = false; 652 653 private ScalarMap xmap; 654 655 private ScalarMap ymap; 656 657 public RubberBandBox(final MultiSpectralDisplay msd, 658 final ScalarMap x, final ScalarMap y) throws VisADException, 659 RemoteException 660 { 661 RealType domainType = msd.getDomainType(); 662 RealType rangeType = msd.getRangeType(); 663 664 LocalDisplay display = msd.getDisplay(); 665 666 rubberBand = new DataReferenceImpl(hashCode() + RBB); 667 rubberBand.setData(new RealTuple(new RealTupleType(domainType, 668 rangeType), new double[] { Double.NaN, Double.NaN })); 669 670 display.addReferences(new RubberBandBoxRendererJ3D(domainType, 671 rangeType, 1, 1), new DataReference[] { rubberBand }, null); 672 673 xmap = x; 674 ymap = y; 675 676 this.addReference(rubberBand); 677 } 678 679 public void doAction() throws VisADException, RemoteException { 680 if (!init) { 681 init = true; 682 return; 683 } 684 685 Gridded2DSet set = (Gridded2DSet)rubberBand.getData(); 686 687 float[] low = set.getLow(); 688 float[] high = set.getHi(); 689 690 xmap.setRange(low[0], high[0]); 691 ymap.setRange(low[1], high[1]); 692 } 693 } 694 695 public static class DragLine extends CellImpl { 696 private final String selectorId = hashCode() + "_selector"; 697 private final String lineId = hashCode() + "_line"; 698 private final String controlId; 699 700 private ConstantMap[] mappings = new ConstantMap[5]; 701 702 private DataReference line; 703 704 private DataReference selector; 705 706 private MultiSpectralDisplay multiSpectralDisplay; 707 708 private RealType domainType; 709 private RealType rangeType; 710 711 private RealTupleType tupleType; 712 713 private LocalDisplay display; 714 715 private float[] YRANGE; 716 717 private float lastSelectedValue; 718 719 public DragLine(final MultiSpectralDisplay msd, final String controlId, final Color color) throws Exception { 720 this(msd, controlId, makeColorMap(color)); 721 } 722 723 public DragLine(final MultiSpectralDisplay msd, final String controlId, final Color color, float[] YRANGE) throws Exception { 724 this(msd, controlId, makeColorMap(color), YRANGE); 725 } 726 727 public DragLine(final MultiSpectralDisplay msd, final String controlId, 728 final ConstantMap[] color) throws Exception 729 { 730 this(msd, controlId, color, new float[] {180f, 320f}); 731 } 732 733 public DragLine(final MultiSpectralDisplay msd, final String controlId, 734 final ConstantMap[] color, float[] YRANGE) throws Exception 735 { 736 if (msd == null) 737 throw new NullPointerException("must provide a non-null MultiSpectralDisplay"); 738 if (controlId == null) 739 throw new NullPointerException("must provide a non-null control ID"); 740 if (color == null) 741 throw new NullPointerException("must provide a non-null color"); 742 743 this.controlId = controlId; 744 this.multiSpectralDisplay = msd; 745 this.YRANGE = YRANGE; 746 lastSelectedValue = multiSpectralDisplay.getWaveNumber(); 747 748 for (int i = 0; i < color.length; i++) { 749 mappings[i] = (ConstantMap)color[i].clone(); 750 } 751 mappings[4] = new ConstantMap(-0.5, Display.YAxis); 752 753 Gridded1DSet domain = multiSpectralDisplay.getDomainSet(); 754 755 domainType = multiSpectralDisplay.getDomainType(); 756 rangeType = multiSpectralDisplay.getRangeType(); 757 tupleType = new RealTupleType(domainType, rangeType); 758 759 selector = new DataReferenceImpl(selectorId); 760 line = new DataReferenceImpl(lineId); 761 762 display = multiSpectralDisplay.getDisplay(); 763 764 display.addReferences(new GrabLineRendererJ3D(domain), new DataReference[] { selector }, new ConstantMap[][] { mappings }); 765 display.addReference(line, cloneMappedColor(color)); 766 767 addReference(selector); 768 } 769 770 private static ConstantMap[] cloneMappedColor(final ConstantMap[] color) throws Exception { 771 assert color != null && color.length >= 3 : color; 772 return new ConstantMap[] { 773 (ConstantMap)color[0].clone(), 774 (ConstantMap)color[1].clone(), 775 (ConstantMap)color[2].clone(), 776 }; 777 } 778 779 public void annihilate() { 780 try { 781 display.removeReference(selector); 782 display.removeReference(line); 783 } catch (Exception e) { 784 LogUtil.logException("DragLine.annihilate", e); 785 } 786 } 787 788 public String getControlId() { 789 return controlId; 790 } 791 792 /** 793 * Handles drag and drop updates. 794 */ 795 public void doAction() throws VisADException, RemoteException { 796 setSelectedValue(getSelectedValue()); 797 } 798 799 public float getSelectedValue() { 800 float val = (float)display.getDisplayRenderer().getDirectAxisValue(domainType); 801 if (Float.isNaN(val)) 802 val = lastSelectedValue; 803 return val; 804 } 805 806 public void setSelectedValue(final float val) throws VisADException, 807 RemoteException 808 { 809 // don't do work for stupid values 810 if ((Float.isNaN(val)) 811 || (selector.getThing() != null && val == lastSelectedValue)) 812 return; 813 814 line.setData(new Gridded2DSet(tupleType, 815 new float[][] { { val, val }, { YRANGE[0], YRANGE[1] } }, 2)); 816 817 selector.setData(new Real(domainType, val)); 818 lastSelectedValue = val; 819 multiSpectralDisplay.updateControlSelector(controlId, val); 820 } 821 } 822}