001 /*
002 * $Id: GeoSubsetRubberBandBox.java,v 1.11 2012/02/19 17:35:45 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
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
031 package edu.wisc.ssec.mcidasv.data;
032
033 import edu.wisc.ssec.mcidasv.data.hydra.MyRubberBandBoxRendererJ3D;
034 import edu.wisc.ssec.mcidasv.data.hydra.SubsetRubberBandBox;
035 //import edu.wisc.ssec.mcidasv.data.hydra.DataToDisplayCoordinateSystem;
036
037 import ucar.unidata.view.geoloc.MapProjectionDisplay;
038 import ucar.visad.display.Displayable;
039 import ucar.visad.display.DisplayMaster;
040 import ucar.visad.display.LineDrawing;
041
042 import visad.*;
043 import visad.bom.*;
044 import visad.georef.MapProjection;
045
046 import java.rmi.RemoteException;
047
048 import java.awt.event.InputEvent;
049
050
051 public class GeoSubsetRubberBandBox extends SubsetRubberBandBox {
052
053 /** x type for the box */
054 private RealType xType;
055
056 /** y type for the box */
057 private RealType yType;
058
059 /** renderer */
060 private MyRubberBandBoxRendererJ3D rubberBandBox;
061
062 /** bounds defined by the rubber band box */
063 private Gridded2DSet bounds;
064
065 /** mouse event mask */
066 private int mask;
067
068 private FlatField data;
069 private boolean isLL;
070 private boolean lastBoxOn;
071
072 private CoordinateSystem dataCS;
073
074 private CoordinateSystem displayCS;
075 private DisplayMaster dispMaster;
076
077 private GeoDataToDisplayCoordinateSystem new_cs;
078
079 private static int count = 0;
080
081 /**
082 * Construct a RubberBandBox using xType as the X coordinate and
083 * yType as the Y coordinate of the box.
084 *
085 * @param xType RealType of the X coordinate of the box
086 * @param yType RealType of the Y coordinate of the box
087 *
088 * @throws VisADException VisAD error
089 * @throws RemoteException Remote error
090 */
091 public GeoSubsetRubberBandBox(FlatField data, CoordinateSystem displayCS)
092 throws VisADException, RemoteException {
093 this(false, data, displayCS, 0);
094 }
095
096 public GeoSubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask)
097 throws VisADException, RemoteException {
098 this(false, data, displayCS, mask);
099 }
100
101 public GeoSubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask)
102 throws VisADException, RemoteException {
103 this(isLL, data, displayCS, mask, true);
104 }
105
106 public GeoSubsetRubberBandBox(FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn)
107 throws VisADException, RemoteException {
108 this(false, data, displayCS, mask, lastBoxOn);
109 }
110
111
112
113 /**
114 * Construct a RubberBandBox using xType as the X coordinate and
115 * yType as the Y coordinate of the box.
116 *
117 * @param xType RealType of the X coordinate of the box
118 * @param yType RealType of the Y coordinate of the box
119 * @param mask key mask to use for rubberbanding
120 *
121 * @throws VisADException VisAD error
122 * @throws RemoteException Remote error
123 */
124 public GeoSubsetRubberBandBox(boolean isLL, FlatField data, CoordinateSystem displayCS, int mask, boolean lastBoxOn)
125 throws VisADException, RemoteException {
126 super(isLL, data, displayCS, mask, lastBoxOn);
127
128 this.data = data;
129 this.displayCS = displayCS;
130 this.isLL = isLL;
131 this.lastBoxOn = lastBoxOn;
132
133 RealTupleType rtype = ((FunctionType)data.getType()).getDomain();
134 dataCS = rtype.getCoordinateSystem();
135 if (dataCS == null) {
136 dataCS = new GridCoordinateSystem((GriddedSet)data.getDomainSet());
137 }
138
139 IdentityCoordinateSystem iCS =
140 new IdentityCoordinateSystem(
141 new RealTupleType(new RealType[] {RealType.getRealType("ZZtop")}));
142
143 CoordinateSystem cs =
144 new CartesianProductCoordinateSystem(new CoordinateSystem[] {dataCS, iCS});
145
146 new_cs = new GeoDataToDisplayCoordinateSystem(isLL, cs, displayCS);
147 resetExtremes();
148
149
150 DisplayRealType displayLineType =
151 new DisplayRealType("displayLine_"+count, true, 0.0, 10000.0, 0.0, null);
152 DisplayRealType displayElemType =
153 new DisplayRealType("displayElem_"+count, true, 0.0, 10000.0, 0.0, null);
154 DisplayRealType displayAltType =
155 new DisplayRealType("displayAlt_"+count, true, -1.0, 1.0, 0.0, null);
156 DisplayTupleType dtt =
157 new DisplayTupleType(new DisplayRealType[] {displayLineType, displayElemType, displayAltType}, new_cs);
158
159 RealType elemType = RealType.getRealType("elem_"+count);
160 RealType lineType = RealType.getRealType("line_"+count);
161 this.xType = lineType;
162 this.yType = elemType;
163 this.mask = mask;
164 bounds = new Gridded2DSet(new RealTupleType(xType, yType), null, 1);
165
166 ScalarMap elemMap = new ScalarMap(elemType, displayElemType);
167 ScalarMap lineMap = new ScalarMap(lineType, displayLineType);
168
169 GriddedSet domainSet = (GriddedSet) data.getDomainSet();
170 float[] low = domainSet.getLow();
171 float[] hi = domainSet.getHi();
172
173 elemMap.setRange(low[1], hi[1]);
174 lineMap.setRange(low[0], hi[0]);
175
176 addScalarMap(elemMap);
177 addScalarMap(lineMap);
178
179 setData(bounds);
180 count += 1;
181 }
182
183 /**
184 * Constructor for creating a RubberBandBox from another instance
185 *
186 * @param that other instance
187 *
188 * @throws VisADException VisAD error
189 * @throws RemoteException Remote error
190 */
191 protected GeoSubsetRubberBandBox(GeoSubsetRubberBandBox that)
192 throws VisADException, RemoteException {
193
194 super(that);
195 }
196
197 protected void setDisplayMaster(DisplayMaster dspMaster) {
198 dispMaster = dspMaster;
199 new_cs.setDisplayMaster(dispMaster);
200 }
201
202 public float[] getRanges() {
203 float[] extrms = new_cs.getExtremes();
204 resetExtremes();
205 return extrms;
206 }
207
208 protected void resetExtremes() {
209 new_cs.resetExtremes();
210 }
211
212 protected GeoDataToDisplayCoordinateSystem getDisplayCoordSystem() {
213 return new_cs;
214 }
215 }
216
217 class GeoDataToDisplayCoordinateSystem extends CoordinateSystem {
218 private CoordinateSystem dataCS;
219 private CoordinateSystem displayCS;
220 private boolean isLL;
221 private MapProjectionDisplay mapProjDisp;
222 private double scaleX;
223 private double scaleY;
224 private double offsetX;
225 private double offsetY;
226
227 private float lineLo;
228 private float lineHi;
229 private float eleLo;
230 private float eleHi;
231
232 GeoDataToDisplayCoordinateSystem(boolean isLL, CoordinateSystem dataCS, CoordinateSystem displayCS) throws VisADException {
233 super(displayCS.getReference(), null);
234 try {
235 this.dataCS = dataCS;
236 this.displayCS = displayCS;
237 this.isLL = isLL;
238 } catch (Exception e) {
239 System.out.println("e=" + e);
240 }
241 }
242
243 protected void setDisplayMaster(DisplayMaster dspMaster) {
244 if (dspMaster instanceof MapProjectionDisplay) {
245 mapProjDisp = (MapProjectionDisplay)dspMaster;
246 this.mapProjDisp = mapProjDisp;
247 MapProjection mapProj = mapProjDisp.getMapProjection();
248 java.awt.geom.Rectangle2D bounds =
249 mapProj.getDefaultMapArea();
250 scaleX = bounds.getWidth() / 2.0;
251 scaleY = bounds.getHeight() / 2.0;
252 offsetX = bounds.getX() + scaleX;
253 offsetY = bounds.getY() + scaleY;
254 }
255 }
256
257 public float[] getExtremes() {
258 float[] extremes = new float[4];
259 extremes[0] = eleLo;
260 extremes[1] = lineLo;
261 extremes[2] = eleHi;
262 extremes[3] = lineHi;
263 return extremes;
264 }
265
266 public void resetExtremes() {
267 lineLo = (float)99999.0;
268 lineHi = (float)0.0;
269 eleLo = (float)99999.0;
270 eleHi = (float)0.0;
271 }
272
273 public float[][] toReference(float[][] values) throws VisADException {
274
275 if (values[0][0] < eleLo) eleLo = values[0][0];
276 if (values[0][0] > eleHi) eleHi = values[0][0];
277 if (values[1][0] < lineLo) lineLo = values[1][0];
278 if (values[1][0] > lineHi) lineHi = values[1][0];
279
280 float[][] new_values = bypassToReference(values);
281 return new_values;
282 }
283
284 private float[][] bypassToReference(float[][] xyz) {
285 if ((xyz == null) || (xyz[0].length < 1)) {
286 return xyz;
287 }
288 int numpoints = xyz[0].length;
289 float x, y;
290 float[]t2ax = xyz[0];
291 float[]t2ay = xyz[1];
292 for (int i = 0; i < numpoints; i++) {
293 float t2x = t2ax[i];
294 float t2y = t2ay[i];
295 if (t2x!=t2x || t2y!=t2y) {
296 x = Float.NaN;
297 y = Float.NaN;
298 } else {
299 x = (float) ((t2x - offsetX) / scaleX);
300 y = (float) ((t2y - offsetY) / scaleY);
301 }
302 xyz[0][i] = x;
303 xyz[1][i] = y;
304 }
305 return xyz;
306 }
307
308 public float[][] fromReference(float[][] values) throws VisADException {
309 float[][] new_values = bypassFromReference(values);
310 return new_values;
311 }
312
313 /**
314 * Transform display XYZ values to latitude/longitude/altitude
315 *
316 * @param xyz array of Display.DisplaySpatialCartesianTuple XYZ values
317 * @return array of display lat/lon/alt values.
318 *
319 * @throws VisADException can't create the necessary VisAD object
320 */
321 private float[][] bypassFromReference(float[][] xyz) throws VisADException {
322 if ((xyz == null) || (xyz[0].length < 1)) {
323 return xyz;
324 }
325 int numpoints = xyz[0].length;
326 for (int i = 0; i < numpoints; i++) {
327 if (Float.isNaN(xyz[0][i]) || Float.isNaN(xyz[0][i])) {
328 continue;
329 }
330 xyz[0][i] = (float) (xyz[0][i] * scaleX + offsetX);
331 xyz[1][i] = (float) (xyz[1][i] * scaleY + offsetY);
332 }
333 return xyz;
334 }
335
336 public double[][] toReference(double[][] values) throws VisADException {
337 //- if (isLL) values = reverseArrayOrder(values);
338 double[][] new_values = dataCS.toReference(values);
339 if (isLL) new_values = reverseArrayOrder(new_values);
340 new_values = displayCS.toReference(new double[][] {new_values[1], new_values[0], new_values[2]});
341 return new_values;
342 }
343
344
345 public double[][] fromReference(double[][] values) throws VisADException {
346 //- if (isLL) values = reverseArrayOrder(values);
347 double[][] new_values = displayCS.fromReference(values);
348 if (isLL) new_values = reverseArrayOrder(new_values);
349 new_values = dataCS.fromReference(new double[][] {new_values[1], new_values[0], new_values[2]});
350 return new_values;
351 }
352
353 public boolean equals(Object obj) {
354 return true;
355 }
356
357 private double[][] reverseArrayOrder(double[][] in) {
358 if (in.length < 2) return in;
359 int len1 = 2;
360 int len2 = in[0].length;
361 double[][] out = new double[in.length][len2];;
362 for (int i=0; i<len1; i++) {
363 for (int j=0; j<len2; j++) {
364 out[len1-i-1][j] = in[i][j];
365 }
366 }
367 if (in.length > 2) {
368 for (int i=2; i<in.length; i++) {
369 for (int j=0; j<len2; j++) {
370 out[i][j] = in[i][j];
371 }
372 }
373 }
374 return out;
375 }
376
377
378 private float[][] reverseArrayOrder(float[][] in) {
379 if (in.length < 2) return in;
380 int len1 = 2;
381 int len2 = in[0].length;
382 float[][] out = new float[in.length][len2];;
383 for (int i=0; i<len1; i++) {
384 for (int j=0; j<len2; j++) {
385 out[len1-i-1][j] = in[i][j];
386 }
387 }
388 if (in.length > 2) {
389 for (int i=2; i<in.length; i++) {
390 for (int j=0; j<len2; j++) {
391 out[i][j] = in[i][j];
392 }
393 }
394 }
395 return out;
396 }
397 }