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