001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.hydra; 030 031import java.rmi.RemoteException; 032 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036import ucar.visad.display.Displayable; 037import ucar.visad.display.LineDrawing; 038import visad.CartesianProductCoordinateSystem; 039import visad.CoordinateSystem; 040import visad.DataRenderer; 041import visad.DisplayRealType; 042import visad.DisplayTupleType; 043import visad.FlatField; 044import visad.FunctionType; 045import visad.GridCoordinateSystem; 046import visad.Gridded2DSet; 047import visad.Gridded3DSet; 048import visad.GriddedSet; 049import visad.IdentityCoordinateSystem; 050import visad.RealTupleType; 051import visad.RealType; 052import visad.ScalarMap; 053import visad.VisADException; 054 055public class SubsetRubberBandBox extends LineDrawing { 056 057 private static final Logger logger = LoggerFactory.getLogger(SubsetRubberBandBox.class); 058 059 /** x type for the box */ 060 private RealType xType; 061 062 /** y type for the box */ 063 private RealType yType; 064 065 /** renderer */ 066 private MyRubberBandBoxRendererJ3D rubberBandBox; 067 068 /** bounds defined by the rubber band box */ 069 private Gridded2DSet bounds; 070 071 /** mouse event mask */ 072 private int mask; 073 074 private boolean lastBoxOn; 075 076 private int elemMax = -1; 077 private int lineMax = -1; 078 079 private CoordinateSystem dataCS; 080 081 private static int count = 0; 082 083 /** 084 * Construct a RubberBandBox using xType as the X coordinate and 085 * yType as the Y coordinate of the box. 086 * 087 * @param data 088 * @param displayCS 089 * 090 * @throws VisADException VisAD error 091 * @throws RemoteException Remote error 092 */ 093 094 public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS) 095 throws VisADException, RemoteException { 096 this(false, data, displayCS, 0); 097 } 098 099 public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask) 100 throws VisADException, RemoteException { 101 this(false, data, displayCS, mask); 102 } 103 104 public SubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask) 105 throws VisADException, RemoteException { 106 this(isLL, data, displayCS, mask, true); 107 } 108 109 public SubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn) 110 throws VisADException, RemoteException { 111 this(false, data, displayCS, mask, lastBoxOn); 112 } 113 114 115 116 /** 117 * Construct a RubberBandBox using xType as the X coordinate and 118 * yType as the Y coordinate of the box. 119 * 120 * @param isLL 121 * @param data 122 * @param displayCS 123 * @param mask Key mask to use for rubberbanding 124 * @param lastBoxOn 125 * 126 * @throws VisADException VisAD error 127 * @throws RemoteException Remote error 128 */ 129 130 public SubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn) 131 throws VisADException, RemoteException { 132 super("Subset Rubber Band Box"); 133 134 this.lastBoxOn = lastBoxOn; 135 136 RealTupleType rtype = ((FunctionType)data.getType()).getDomain(); 137 dataCS = rtype.getCoordinateSystem(); 138 if (dataCS == null) { 139 dataCS = new GridCoordinateSystem((GriddedSet)data.getDomainSet()); 140 } 141 142 IdentityCoordinateSystem iCS = 143 new IdentityCoordinateSystem( 144 new RealTupleType(new RealType[] {RealType.getRealType("ZZtop")})); 145 146 CoordinateSystem cs = 147 new CartesianProductCoordinateSystem(new CoordinateSystem[] {dataCS, iCS}); 148 149 CoordinateSystem new_cs = new DataToDisplayCoordinateSystem(isLL, cs, displayCS); 150 151 152 DisplayRealType displayLineType = 153 new DisplayRealType("displayLine_"+count, true, 0.0, 10000.0, 0.0, null); 154 DisplayRealType displayElemType = 155 new DisplayRealType("displayElem_"+count, true, 0.0, 10000.0, 0.0, null); 156 DisplayRealType displayAltType = 157 new DisplayRealType("displayAlt_"+count, true, -1.0, 1.0, 0.0, null); 158 DisplayTupleType dtt = 159 new DisplayTupleType(new DisplayRealType[] {displayLineType, displayElemType, displayAltType}, new_cs); 160 161 162 RealType elemType = RealType.getRealType("elem_"+count); 163 RealType lineType = RealType.getRealType("line_"+count); 164 this.xType = lineType; 165 this.yType = elemType; 166 this.mask = mask; 167 bounds = new Gridded2DSet(new RealTupleType(xType, yType), null, 1); 168 169 ScalarMap elemMap = new ScalarMap(elemType, displayElemType); 170 ScalarMap lineMap = new ScalarMap(lineType, displayLineType); 171 172 GriddedSet domainSet = (GriddedSet) data.getDomainSet(); 173 float[] low = domainSet.getLow(); 174 float[] hi = domainSet.getHi(); 175 176 logger.trace("{}: element range: {} to {}", hashCode(), low[1], hi[1]); 177 logger.trace("{}: line range: {} to {}", hashCode(), low[0], hi[0]); 178 179 elemMax = (int) hi[1]; 180 lineMax = (int) hi[0]; 181 182 elemMap.setRange(low[1], hi[1]); 183 lineMap.setRange(low[0], hi[0]); 184 185 addScalarMap(elemMap); 186 addScalarMap(lineMap); 187 188 setData(bounds); 189 count += 1; 190 } 191 192 /** 193 * Constructor for creating a RubberBandBox from another instance 194 * 195 * @param that other instance 196 * 197 * @throws VisADException VisAD error 198 * @throws RemoteException Remote error 199 */ 200 protected SubsetRubberBandBox(SubsetRubberBandBox that) 201 throws VisADException, RemoteException { 202 203 super(that); 204 205 this.xType = that.xType; 206 this.yType = that.yType; 207 this.bounds = that.bounds; 208 } 209 210 /** 211 * Invoked when box mouse is released. Subclasses should invoke 212 * super.dataChange() to ensure the the bounds are set. 213 * 214 * @throws RemoteException 215 * @throws VisADException 216 */ 217 218 protected void dataChange() throws VisADException, RemoteException { 219 bounds = (Gridded2DSet) getData(); 220 float[] highs = bounds.getHi(); 221 float[] lows = bounds.getLow(); 222 if (highs != null && lows != null) super.dataChange(); 223 } 224 225 /** 226 * Return the bounds of the RubberBandBox. The Gridded2DSet that 227 * is returned contains the opposite (starting and ending) corners 228 * of the box. 229 * 230 * @return set containing the opposite corners of the box. 231 */ 232 233 public Gridded2DSet getBounds() { 234 return bounds; 235 } 236 237 /** 238 * @return the elemMax 239 */ 240 public int getElemMax() { 241 return elemMax; 242 } 243 244 /** 245 * @return the lineMax 246 */ 247 public int getLineMax() { 248 return lineMax; 249 } 250 251 /** 252 * Get the DataRenderer used for this displayable. 253 * 254 * @return RubberBandBoxRendererJ3D associated with this displayable 255 */ 256 257 protected DataRenderer getDataRenderer() { 258 rubberBandBox = new MyRubberBandBoxRendererJ3D(xType, yType, mask, 259 mask); 260 rubberBandBox.setKeepLastBoxOn(lastBoxOn); 261 262 return rubberBandBox; 263 } 264 265 /** 266 * Returns a clone of this instance suitable for another VisAD display. 267 * Underlying data objects are not cloned. 268 * 269 * @return A semi-deep clone of this instance. 270 * 271 * @throws VisADException VisAD failure. 272 * @throws RemoteException Java RMI failure. 273 */ 274 public Displayable cloneForDisplay() 275 throws RemoteException, VisADException { 276 return new SubsetRubberBandBox(this); 277 } 278 279 public void setBox(SubsetRubberBandBox rbb) { 280 rubberBandBox.setLastBox((MyRubberBandBoxRendererJ3D)rbb.getDataRenderer()); 281 } 282 283 public Gridded3DSet getLastBox() { 284 return rubberBandBox.last_box; 285 } 286} 287 288 289class DataToDisplayCoordinateSystem extends CoordinateSystem { 290 291 private static final long serialVersionUID = 1L; 292 private CoordinateSystem dataCS; 293 private CoordinateSystem displayCS; 294 private boolean isLL; 295 296 DataToDisplayCoordinateSystem(boolean isLL, CoordinateSystem dataCS, CoordinateSystem displayCS) throws VisADException { 297 super(displayCS.getReference(), null); 298 try { 299 this.dataCS = dataCS; 300 this.displayCS = displayCS; 301 this.isLL = isLL; 302 } catch (Exception e) { 303 System.out.println("e=" + e); 304 } 305 } 306 307 public float[][] toReference(float[][] values) throws VisADException { 308 //- if (isLL) values = reverseArrayOrder(values); 309 float[][] new_values = dataCS.toReference(values); 310 if (isLL) new_values = reverseArrayOrder(new_values); 311 new_values = displayCS.toReference(new float[][] {new_values[1], new_values[0], new_values[2]}); 312 return new_values; 313 } 314 315 public float[][] fromReference(float[][] values) throws VisADException { 316 //- if (isLL) values = reverseArrayOrder(values); 317 float[][] new_values = displayCS.fromReference(values); 318 if (isLL) new_values = reverseArrayOrder(new_values); 319 new_values = dataCS.fromReference(new float[][] {new_values[1], new_values[0], new_values[2]}); 320 321 return new_values; 322 } 323 324 public double[][] toReference(double[][] values) throws VisADException { 325 //- if (isLL) values = reverseArrayOrder(values); 326 double[][] new_values = dataCS.toReference(values); 327 if (isLL) new_values = reverseArrayOrder(new_values); 328 new_values = displayCS.toReference(new double[][] {new_values[1], new_values[0], new_values[2]}); 329 330 return new_values; 331 } 332 333 public double[][] fromReference(double[][] values) throws VisADException { 334 //- if (isLL) values = reverseArrayOrder(values); 335 double[][] new_values = displayCS.fromReference(values); 336 if (isLL) new_values = reverseArrayOrder(new_values); 337 new_values = dataCS.fromReference(new double[][] {new_values[1], new_values[0], new_values[2]}); 338 return new_values; 339 } 340 341 public boolean equals(Object obj) { 342 return true; 343 } 344 345 private double[][] reverseArrayOrder(double[][] in) { 346 if (in.length < 2) return in; 347 int len1 = 2; 348 int len2 = in[0].length; 349 double[][] out = new double[in.length][len2];; 350 for (int i=0; i<len1; i++) { 351 for (int j=0; j<len2; j++) { 352 out[len1-i-1][j] = in[i][j]; 353 } 354 } 355 if (in.length > 2) { 356 for (int i=2; i<in.length; i++) { 357 for (int j=0; j<len2; j++) { 358 out[i][j] = in[i][j]; 359 } 360 } 361 } 362 return out; 363 } 364 365 366 private float[][] reverseArrayOrder(float[][] in) { 367 if (in.length < 2) return in; 368 int len1 = 2; 369 int len2 = in[0].length; 370 float[][] out = new float[in.length][len2];; 371 for (int i=0; i<len1; i++) { 372 for (int j=0; j<len2; j++) { 373 out[len1-i-1][j] = in[i][j]; 374 } 375 } 376 if (in.length > 2) { 377 for (int i=2; i<in.length; i++) { 378 for (int j=0; j<len2; j++) { 379 out[i][j] = in[i][j]; 380 } 381 } 382 } 383 return out; 384 } 385}