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 029package edu.wisc.ssec.mcidasv.data.hydra; 030 031import java.rmi.RemoteException; 032 033import ucar.unidata.data.grid.GridUtil; 034import ucar.visad.display.DisplayableData; 035import ucar.visad.display.GridDisplayable; 036import ucar.visad.display.ScalarMapSet; 037 038import visad.BadMappingException; 039import visad.BaseColorControl; 040import visad.ConstantMap; 041import visad.DataRenderer; 042import visad.Display; 043import visad.DisplayException; 044import visad.DisplayRealType; 045import visad.FieldImpl; 046import visad.GraphicsModeControl; 047import visad.LocalDisplay; 048import visad.RealTupleType; 049import visad.RealType; 050import visad.ScalarMap; 051import visad.ScalarMapControlEvent; 052import visad.ScalarMapEvent; 053import visad.ScalarMapListener; 054import visad.Set; 055import visad.TupleType; 056import visad.VisADException; 057import visad.bom.ImageRendererJ3D; 058 059/** 060 * Provides support for a Displayable that needs a map to 061 * (Display.Red,Display.Green,Display.Blue) 062 * 063 * @author IDV development team 064 * @version $Revision$ 065 */ 066public class ImageRGBDisplayable extends DisplayableData implements GridDisplayable { 067 068 /** color ScalarMaps */ 069 private volatile ScalarMap[] colorMaps = { null, null, null }; 070 071 /** color MathType */ 072 private volatile RealTupleType colorTupleType; 073 074 /** color palette */ 075 private float[][] colorPalette; 076 077 /** What do we map with */ 078 private DisplayRealType mapType = Display.RGB; 079 080 /** flag for whether we use Alpha channel or not */ 081 private boolean doAlpha = false; 082 083 /** 084 * Constructs from a name for the Displayable and the type of the 085 * RGB parameter. 086 * 087 * @param name The name for the displayable. 088 * @throws VisADException VisAD failure. 089 * @throws RemoteException Java RMI failure. 090 */ 091 092 public ImageRGBDisplayable(String name) 093 throws VisADException, RemoteException { 094 this(name, false); 095 } 096 097 /** 098 * Constructs from a name for the Displayable and the type of the 099 * RGB parameter. 100 * 101 * @param name The name for the displayable. 102 * @param doAlpha true to map to RGBA 103 * @throws VisADException VisAD failure. 104 * @throws RemoteException Java RMI failure. 105 */ 106 107 public ImageRGBDisplayable(String name, boolean doAlpha) 108 throws VisADException, RemoteException { 109 this(name, BaseColorControl.initTableGreyWedge(new float[(doAlpha) 110 ? 4 111 : 3][255]), doAlpha); 112 } 113 114 /** 115 * Constructs from a name for the Displayable and the type of the 116 * RGB parameter. 117 * 118 * @param name The name for the displayable. 119 * @param colorPalette The color palette 120 * @param doAlpha true to map to RGBA 121 * @throws VisADException VisAD failure. 122 * @throws RemoteException Java RMI failure. 123 */ 124 125 public ImageRGBDisplayable(String name, float[][] colorPalette, 126 boolean doAlpha) 127 throws VisADException, RemoteException { 128 this(name, colorPalette, doAlpha, null); 129 } 130 131 /** 132 * Constructs from another instance. The following attributes are set from 133 * the other instance: color palette, the color RealType. 134 * @param that The other instance. 135 * @throws VisADException VisAD failure. 136 * @throws RemoteException Java RMI failure. 137 */ 138 139 protected ImageRGBDisplayable(ImageRGBDisplayable that) 140 throws VisADException, RemoteException { 141 142 super(that); 143 this.doAlpha = that.doAlpha; 144 colorTupleType = that.colorTupleType; 145 colorPalette = Set.copyFloats(that.colorPalette); 146 if (colorTupleType != null) { 147 setColorMaps(); 148 } 149 } 150 151 public ImageRGBDisplayable(String name, float[][] colorPalette, boolean doAlpha, FieldImpl field) 152 throws VisADException, RemoteException { 153 super(name); 154 this.doAlpha = doAlpha; 155 if (doAlpha) { 156 mapType = Display.RGBA; 157 colorMaps = new ScalarMap[] { null, null, null, null }; 158 } 159 160 addConstantMaps(new ConstantMap[] { 161 new ConstantMap(GraphicsModeControl.SUM_COLOR_MODE, 162 Display.ColorMode), 163 new ConstantMap(1.0, Display.MissingTransparent) }); 164 165 166 if (field != null) { 167 TupleType tt = GridUtil.getParamType(field); 168 RealTupleType ffldType = new RealTupleType(tt.getRealComponents()); 169 170 if ((getColorTupleType() == null) 171 || !ffldType.equals(getColorTupleType())) { 172 setColorTupleType(ffldType); 173 } 174 } 175 } 176 177 /** 178 * Set the data into the Displayable; set RGB Type 179 * 180 * 181 * @param field an image or sequence of images 182 * @exception VisADException from construction of VisAd objects 183 * @exception RemoteException from construction of VisAD objects 184 */ 185 186 public void loadData(FieldImpl field) 187 throws VisADException, RemoteException { 188 setData(field); 189 } 190 191 192 /** 193 * Get the RealTupleType of the RGB parameter. 194 * @return The RealTupleType of the RGB parameters. 195 * May be {@code null}. 196 */ 197 public RealTupleType getColorTupleType() { 198 return colorTupleType; 199 } 200 201 /** 202 * Sets the RealTupleType of the RGB parameter. 203 * @param realTupleType The RealTupleType of the RGB parameters. May 204 * not be {@code null}. 205 * @throws VisADException VisAD failure. 206 * @throws RemoteException Java RMI failure. 207 */ 208 protected void setColorTupleType(RealTupleType realTupleType) 209 throws RemoteException, VisADException { 210 211 if ( !realTupleType.equals(colorTupleType)) { 212 colorTupleType = realTupleType; 213 setColorMaps(); 214 } 215 } 216 217 218 /** 219 * Returns the RealTupleType of the RGB parameter. 220 * @return The RealTupleType of the color parameter. May 221 * be {@code null}. 222 * @deprecated use getColorTupleType() 223 */ 224 public RealTupleType getRGBRealTupleType() { 225 return colorTupleType; 226 } 227 228 229 /** 230 * Sets the set of ScalarMap-s of this instance. The ScalarMap-s of 231 * this instance will be added to the set before the SCALAR_MAP_SET 232 * property is set. This method fires a PropertyChangeEvent for 233 * SCALAR_MAP_SET with {@code null} for the old value and the new 234 * set of ScalarMap-s for the new Value. Intermediate subclasses that 235 * have their own ScalarMap-s should override this method and invoke 236 * {@code super.setScalarMaps(ScalarMapSet)}. 237 * @param maps The set of ScalarMap-s to be added. 238 * @throws BadMappingException The RealType of the color parameter 239 * has not been set or its ScalarMap is already in 240 * the set. 241 */ 242 protected void setScalarMaps(ScalarMapSet maps) 243 throws BadMappingException { 244 245 if (colorMaps[0] == null) { 246 throw new BadMappingException(getClass().getName() 247 + ".setScalarMaps(ScalarMapSet): " 248 + "Color not yet set"); 249 } 250 251 for (int i = 0; i < colorMaps.length; i++) { 252 maps.add(colorMaps[i]); 253 } 254 super.setScalarMapSet(maps); 255 } 256 257 /** 258 * Set the alpha. Unused. 259 * 260 * @param alpha alpha 261 * 262 * @throws RemoteException On badness 263 * @throws VisADException On badness 264 */ 265 public void setAlpha(float alpha) throws RemoteException, VisADException { 266 addConstantMaps(new ConstantMap[] { 267 new ConstantMap(alpha, Display.Alpha) }); 268 } 269 270 /** 271 * creates the ScalarMaps for color for this Displayable. 272 * 273 * @throws VisADException VisAD failure. 274 * @throws RemoteException Java RMI failure. 275 */ 276 private void setColorMaps() throws RemoteException, VisADException { 277 278 ScalarMapSet set = new ScalarMapSet(); 279 for (int i = 0; i < colorMaps.length; i++) { 280 colorMaps[i] = 281 new ScalarMap((RealType) colorTupleType.getComponent(i), 282 mapType); 283 /* TODO: maybe allow user to set range. If so, just copy 284 logic from RGBDisplayable */ 285 //-TDR colorMaps[i].setRange(0, 255); 286 set.add(colorMaps[i]); 287 final int colorMapIndex = i; 288 colorMaps[i].addScalarMapListener(new ScalarMapListener() { 289 public void controlChanged(ScalarMapControlEvent event) 290 throws RemoteException, VisADException { 291 int id = event.getId(); 292 if ((id == ScalarMapEvent.CONTROL_ADDED) 293 || (id == ScalarMapEvent.CONTROL_REPLACED)) { 294 setColorsInControls(colorPalette, colorMapIndex); 295 } 296 } 297 298 public void mapChanged(ScalarMapEvent event) 299 throws RemoteException, VisADException { 300 } 301 }); 302 } 303 304 setScalarMapSet(set); 305 setColorsInControls(colorPalette); 306 } 307 308 /** 309 * Set the display. 310 * 311 * @param display display to set this into 312 * 313 * @throws DisplayException Display type exception 314 * @throws RemoteException Java RMI error 315 * @throws VisADException problem creating VisAD object 316 */ 317 public void setDisplay(LocalDisplay display) 318 throws DisplayException, VisADException, RemoteException { 319 super.setDisplay(display); 320 setColorsInControls(colorPalette); 321 } 322 323 /** 324 * This method sets the color palette 325 * according to the color table in argument; 326 * pair this method with setRange(lo,high) to get 327 * a fixed association of color table and range of values. 328 * 329 * @param colorPalette the color table or color-alpha table desired 330 * @throws VisADException if a core VisAD failure occurs. 331 * @throws RemoteException if a Java RMI failure occurs. 332 */ 333 public void setColorPalette(float[][] colorPalette) 334 throws RemoteException, VisADException { 335 336 setColorsInControls(colorPalette); 337 this.colorPalette = colorPalette; 338 } 339 340 /** 341 * Return the current color palette in this Displayable 342 * 343 * @return a color table float[3][len] or color-alpha table float[4][len] 344 */ 345 public float[][] getColorPalette() { 346 return colorPalette; 347 } 348 349 350 /** 351 * Set colors for the controls of all color maps. 352 * 353 * @param colorPalette The 3xN color palette array 354 * 355 * @throws RemoteException Java RMI error 356 * @throws VisADException problem creating VisAD object 357 */ 358 private void setColorsInControls(float[][] colorPalette) 359 throws RemoteException, VisADException { 360 361 for (int i = 0; i < colorMaps.length; i++) { 362 setColorsInControls(colorPalette, i); 363 } 364 } 365 366 367 368 369 /** 370 * Set colors for the control defined by the given colorMapIndex (0, 1, or 2). 371 * 372 * @param colorPalette The 3xN color palette array 373 * @param colorMapIndex Which of the color maps are we setting the color of. 374 * 375 * @throws RemoteException Java RMI error 376 * @throws VisADException problem creating VisAD object 377 */ 378 private void setColorsInControls(float[][] colorPalette, 379 int colorMapIndex) 380 throws RemoteException, VisADException { 381 if (colorPalette == null) { 382 return; 383 } 384 385 386 if (colorMaps[colorMapIndex] == null) { 387 return; 388 } 389 390 BaseColorControl bcc = 391 (BaseColorControl) colorMaps[colorMapIndex].getControl(); 392 393 if (bcc != null) { 394 float[][] table = 395 new float[colorMaps.length][colorPalette[0].length]; 396 table[colorMapIndex] = colorPalette[colorMapIndex]; 397 bcc.setTable(table); 398 } 399 } 400 401 protected DataRenderer getDataRenderer() throws VisADException { 402 403 ImageRendererJ3D myRenderer = new ImageRendererJ3D(); 404 return myRenderer; 405 406 } 407 408 409 /** 410 * Set whether this GridDisplayable should have the data colored 411 * by another parameter. This implementation is a no-op. 412 * 413 * @param yesno true if colored by another 414 */ 415 public void setColoredByAnother(boolean yesno) {} 416 417}