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.HydraRGBDisplayable;
032 import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralData;
033 import edu.wisc.ssec.mcidasv.control.LambertAEA;
034
035 import java.awt.BorderLayout;
036 import java.awt.Color;
037 import java.awt.geom.Rectangle2D;
038 import java.awt.event.ComponentEvent;
039 import java.awt.event.ComponentListener;
040 import java.net.URL;
041 import java.rmi.RemoteException;
042
043 import javax.swing.*;
044
045 import ucar.unidata.data.DataChoice;
046 import ucar.unidata.data.DataSelection;
047 import ucar.unidata.data.DataSourceImpl;
048 import ucar.unidata.data.DataSelectionComponent;
049 import ucar.unidata.data.GeoSelection;
050 import ucar.unidata.data.grid.GridUtil;
051 import ucar.unidata.idv.IdvObjectStore;
052 import ucar.unidata.idv.MapViewManager;
053 import ucar.unidata.util.Range;
054 import ucar.unidata.view.geoloc.MapProjectionDisplay;
055 import ucar.unidata.view.geoloc.MapProjectionDisplayJ3D;
056 import ucar.visad.display.DisplayMaster;
057 import ucar.visad.display.MapLines;
058
059 import visad.*;
060 import visad.data.mcidas.AREACoordinateSystem;
061 import visad.data.mcidas.BaseMapAdapter;
062 import ucar.visad.display.Displayable;
063 import ucar.visad.display.LineDrawing;
064 import visad.georef.MapProjection;
065 import org.slf4j.Logger;
066 import org.slf4j.LoggerFactory;
067
068
069 public class GeoPreviewSelection extends DataSelectionComponent {
070
071 private static final Logger logger = LoggerFactory.getLogger(GeoPreviewSelection.class);
072 DataChoice dataChoice;
073 FlatField image;
074 boolean isLL;
075 MapProjection sampleProjection;
076
077 double[] x_coords = new double[2];
078 double[] y_coords = new double[2];
079 MapProjectionDisplayJ3D mapProjDsp;
080 DisplayMaster dspMaster;
081 MapViewManager mvm;
082 IdvObjectStore store;
083
084 final private GeoSubsetRubberBandBox rbb;
085 private int lineMag;
086 private int elementMag;
087
088 private GeoLatLonSelection laloSel;
089
090 private LineDrawing box;
091
092 public GeoPreviewSelection(DataSourceImpl dataSource,
093 DataChoice dataChoice, FlatField image,
094 GeoLatLonSelection laLoSel,
095 MapProjection sample, int lMag, int eMag, boolean showPreview)
096 throws VisADException, RemoteException {
097 super("Region");
098
099 this.dataChoice = dataChoice;
100 this.image = image;
101 this.laloSel = laLoSel;
102 this.sampleProjection = sample;
103
104 if (lMag == 0) lMag = 1;
105 if (eMag == 0) eMag = 1;
106 this.lineMag = lMag;
107 this.elementMag = eMag;
108 sample = getDataProjection();
109
110 if (this.sampleProjection == null) {
111 this.sampleProjection = sample;
112 }
113
114 isLL = sampleProjection.isLatLonOrder();
115 mapProjDsp = new MapProjectionDisplayJ3D(MapProjectionDisplay.MODE_2Din3D);
116 mapProjDsp.enableRubberBanding(false);
117 dspMaster = mapProjDsp;
118 mapProjDsp.setMapProjection(sampleProjection);
119 RealType imageRangeType = (((FunctionType)image.getType()).getFlatRange().getRealComponents())[0];
120 HydraRGBDisplayable imageDsp = new HydraRGBDisplayable("image", imageRangeType, null, true, null);
121
122 if (showPreview) imageDsp.setData(image);
123
124 MapLines mapLines = new MapLines("maplines");
125 URL mapSource = mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPU");
126 try {
127 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
128 mapLines.setMapLines(mapAdapter.getData());
129 mapLines.setColor(java.awt.Color.cyan);
130 mapProjDsp.addDisplayable(mapLines);
131 } catch (Exception excp) {
132 logger.error("can't open map file="+mapSource, excp);
133 }
134
135 mapLines = new MapLines("maplines");
136 mapSource = mapProjDsp.getClass().getResource("/auxdata/maps/OUTLSUPW");
137 try {
138 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
139 mapLines.setMapLines(mapAdapter.getData());
140 mapLines.setColor(java.awt.Color.cyan);
141 mapProjDsp.addDisplayable(mapLines);
142 } catch (Exception excp) {
143 logger.error("can't open map file="+mapSource, excp);
144 }
145
146 mapLines = new MapLines("maplines");
147 mapSource = mapProjDsp.getClass().getResource("/auxdata/maps/OUTLHPOL");
148 try {
149 BaseMapAdapter mapAdapter = new BaseMapAdapter(mapSource);
150 mapLines.setMapLines(mapAdapter.getData());
151 mapLines.setColor(java.awt.Color.cyan);
152 mapProjDsp.addDisplayable(mapLines);
153 } catch (Exception excp) {
154 logger.error("can't open map file="+mapSource, excp);
155 }
156
157 if (showPreview) {
158 dspMaster.addDisplayable(imageDsp);
159 }
160 rbb = new GeoSubsetRubberBandBox(isLL, image, ((MapProjectionDisplay)mapProjDsp).getDisplayCoordinateSystem(), 1);
161 mvm = new MapViewManager(dataSource.getDataContext().getIdv());
162 store = dataSource.getDataContext().getIdv().getStore();
163 rbb.setColor((Color)store.get(mvm.PREF_FGCOLOR, Color.GREEN));
164 rbb.addAction(new CellImpl() {
165 public void doAction() throws VisADException, RemoteException {
166 eraseBox();
167 forceCoords();
168 }
169 });
170 addRBB();
171 makeBox();
172
173 dspMaster.draw();
174 ScalarMap colorMap = imageDsp.getColorMap();
175 if (showPreview) {
176 Range[] range = GridUtil.fieldMinMax(this.image);
177 Range imageRange = range[0];
178 int max;
179 int min;
180 double dMax = imageRange.getMax();
181 double dMin = imageRange.getMin();
182 String name = this.dataChoice.getName();
183 DataSelection ds = this.dataChoice.getDataSelection();
184 if (ds != null) {
185 GeoSelection gs = ds.getGeoSelection();
186 }
187 if (name.endsWith("TEMP")) {
188 min = (int)(dMax);
189 max = (int)(dMin);
190 } else {
191 max = (int)(dMin);
192 min = (int)(dMax);
193 }
194 colorMap.setRange(min, max);
195 BaseColorControl clrCntrl = (BaseColorControl) colorMap.getControl();
196 clrCntrl.setTable(BaseColorControl.initTableGreyWedge(new float[4][256], true));
197 }
198 }
199
200 public MapProjection getDataProjection() {
201 MapProjection mp = null;
202 Rectangle2D rect = MultiSpectralData.getLonLatBoundingBox(image);
203 try {
204 mp = new LambertAEA(rect);
205 } catch (Exception e) {
206 logger.error("error while attempting to create new LambertAEA", e);
207 }
208 return mp;
209 }
210
211 public void initBox() {
212 this.drawBox();
213 }
214
215 protected JComponent doMakeContents() {
216 try {
217 JPanel panel = new JPanel(new BorderLayout());
218 panel.add("Center", dspMaster.getDisplayComponent());
219 panel.addComponentListener (new ComponentListener() {
220 public void componentHidden(ComponentEvent ce) {
221 dspMaster.getDisplayComponent().setVisible(false);
222 }
223 public void componentShown(ComponentEvent ce) {
224 dspMaster.getDisplayComponent().setVisible(true);
225 drawBox();
226 rbb.resetExtremes();
227 }
228 public void componentMoved(ComponentEvent ce) {
229 }
230 public void componentResized(ComponentEvent ce) {
231 }
232 });
233 return panel;
234 }
235 catch (Exception e) {
236 logger.error("error building preview panel", e);
237 }
238 return null;
239 }
240
241 public void setDataChoice(DataChoice choice) {
242 logger.trace("oldChoice={} newChoice={}", this.dataChoice, choice);
243 this.dataChoice = choice;
244 }
245 public DataChoice getDataChoice() {
246 return this.dataChoice;
247 }
248
249 private void forceCoords() {
250 float[] extrms = rbb.getRanges();
251 x_coords[0] = (double)extrms[0];
252 y_coords[0] = (double)extrms[1];
253 x_coords[1] = (double)extrms[2];
254 y_coords[1] = (double)extrms[3];
255
256 int height = (int)(y_coords[1] - y_coords[0]);
257 int width = (int)(x_coords[1] - x_coords[0]);
258 if ((height < 1) || (width < 1)) return;
259
260 if (laloSel != null) {
261 int lineMid = (int)((y_coords[0] + y_coords[1])/2.0 + 0.5);
262 int eleMid = (int)((x_coords[0] + x_coords[1])/2.0 + 0.5);
263 double uLLine = y_coords[1];
264 double uLEle = x_coords[0];
265 if (height < 0) {
266 height *= -1;
267 uLLine = y_coords[0];
268 }
269 if (width < 0) {
270 width *= -1;
271 uLEle = x_coords[1];
272 }
273
274 int line = lineMid;
275 int ele = eleMid;
276 if (laloSel.getPlace().equals(laloSel.PLACE_ULEFT)) {
277 line = (int)Math.floor(uLLine + 0.5);
278 ele = (int)Math.floor(uLEle + 0.5);
279 }
280
281 int linRes = laloSel.getPreviewLineRes();
282 int eleRes = laloSel.getPreviewEleRes();
283
284 height *= linRes;
285 width *= eleRes;
286 laloSel.setBaseNumLines(height);
287 laloSel.setBaseNumElements(width);
288
289 this.lineMag = laloSel.getLineMag();
290 this.elementMag = laloSel.getElementMag();
291 if (lineMag > 0) {
292 height *= lineMag;
293 } else if (lineMag < 0) {
294 height /= -lineMag;
295 }
296 if (elementMag > 0) {
297 width *= elementMag;
298 } else if (elementMag < 0) {
299 width /= -elementMag;
300 }
301
302 Rectangle2D mapArea = sampleProjection.getDefaultMapArea();
303 double previewXDim = mapArea.getWidth();
304 double previewYDim = mapArea.getHeight();
305 double dLin = (double)line;
306 double dEle = (double)ele;
307 if ((line < 0) || (dLin > previewYDim) ||
308 (ele < 0) || (dEle > previewXDim)) {
309 line = -1;
310 ele = -1;
311 }
312
313 // boolean lock = laloSel.getLockOn();
314 // laloSel.setLockOn(true);
315 // int lineMag = 1;
316 // int eleMag = 1;
317 laloSel.setNumLines(height);
318 laloSel.setNumEles(width);
319 // laloSel.setBaseNumLines(height);
320 // laloSel.setBaseNumElements(width);
321 // laloSel.setLineMag(lineMag);
322 // laloSel.setElementMag(eleMag);
323 // laloSel.lineMagSlider.setValue(lineMag);
324 // laloSel.setLRes(-1.0);
325 // laloSel.elementMagSlider.setValue(eleMag);
326 // laloSel.setERes(-1.0);
327 // laloSel.amUpdating = true;
328 // laloSel.lineMagSliderChanged(false);
329 // laloSel.elementMagSliderChanged(false);
330 // laloSel.amUpdating = false;
331 // laloSel.setLockOn(lock);
332
333 laloSel.getGeoLocationInfo(line, ele);
334 String type = laloSel.getCoordinateType();
335 int pos = 0;
336 if (laloSel.getPlace().equals(laloSel.PLACE_ULEFT)) pos = 1;
337 if (type.equals(laloSel.TYPE_LATLON)) {
338 double[][] pts = laloSel.getLatLonPoints();
339 laloSel.setLatitude(pts[0][pos]);
340 laloSel.setLongitude(pts[1][pos]);
341 laloSel.convertToLineEle();
342 } else {
343 double[][] pts = laloSel.getImagePoints();
344 if (type.equals(laloSel.TYPE_AREA))
345 pts = laloSel.getAreaPoints();
346 laloSel.setElement((int)Math.floor(pts[0][pos] + 0.5));
347 laloSel.setLine((int)Math.floor(pts[1][pos] + 0.5));
348 laloSel.setLineElement();
349 laloSel.convertToLatLon();
350 }
351 }
352 }
353
354 @Override public void applyToDataSelection(DataSelection dataSelection) {
355 }
356
357 @Override public boolean getShowInControlProperties() {
358 return false;
359 }
360
361 public void drawBox() {
362 if (box == null) makeBox();
363 removeRBB();
364
365 double[][] elelin = laloSel.getDisplayELPoints();
366 if (elelin == null) return;
367
368 for (int i=0; i<2; i++) {
369 for (int j=0; j<5; j++) {
370 Double val = new Double(elelin[i][j]);
371 if (val.isNaN()) {
372 eraseBox();
373 return;
374 }
375 }
376 }
377
378 float[][] floatVals = new float[][] {
379 { (float)elelin[0][0], (float)elelin[0][1], (float)elelin[0][2],
380 (float)elelin[0][3], (float)elelin[0][4] },
381 { (float)elelin[1][0], (float)elelin[1][1], (float)elelin[1][2],
382 (float)elelin[1][3], (float)elelin[1][4] }};
383
384 float[][] dispVals = new float[][] {
385 { floatVals[0][1], floatVals[0][2], floatVals[0][4],
386 floatVals[0][3], floatVals[0][1] },
387 { floatVals[1][1], floatVals[1][2], floatVals[1][4],
388 floatVals[1][3], floatVals[1][1] }
389 };
390
391 try {
392 float[][] refVals = rbb.getDisplayCoordSystem().toReference(dispVals);
393 Gridded2DSet set = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple,
394 refVals, 5);
395 box.setData(set);
396 } catch (Exception e) {
397 logger.error("error drawing box", e);
398 }
399 }
400
401 private void makeBox() {
402 if (box == null) {
403 try {
404 box = new LineDrawing("box");
405 box.setColor((Color)store.get(mvm.PREF_FGCOLOR, Color.GREEN));
406 dspMaster.addDisplayable(box);
407 } catch (Exception e) {
408 logger.error("error making box", e);
409 }
410 }
411 }
412
413 private void eraseBox() {
414 Gridded2DSet set = null;
415 if (box == null) makeBox();
416 try {
417 set = new Gridded2DSet(RealTupleType.LatitudeLongitudeTuple,
418 new float[][] {
419 { (float)0.0, (float)0.0 },
420 { (float)0.0, (float)0.0 },
421 }, 2);
422 box.setData(set);
423 } catch (Exception e) {
424 logger.error("error erasing box", e);
425 }
426 addRBB();
427 }
428
429 private boolean rBBPresent() {
430 Displayable[] dsps = dspMaster.getDisplayables();
431 if (dsps.length > 0) {
432 for (int i = 0; i < dsps.length; i++) {
433 Displayable disp = dsps[i];
434 if (disp == (Displayable)rbb) {
435 return true;
436 }
437 }
438 }
439 return false;
440 }
441
442 private void removeRBB() {
443 if (rBBPresent()) {
444 try {
445 dspMaster.removeDisplayable(rbb);
446 } catch (Exception e) {
447 logger.error("error removing rubberband box", e);
448 }
449 }
450 addRBB();
451 }
452
453 private void addRBB() {
454 if (!rBBPresent()) {
455 try {
456 dspMaster.addDisplayable(rbb);
457 } catch (Exception e) {
458 logger.error("error adding rubberband box", e);
459 }
460 }
461 }
462 }