001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2015
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;
030
031import edu.wisc.ssec.mcidasv.data.hydra.HydraRGBDisplayable;
032import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralData;
033import edu.wisc.ssec.mcidasv.control.LambertAEA;
034
035import java.awt.BorderLayout;
036import java.awt.Color;
037import java.awt.geom.Rectangle2D;
038import java.awt.event.ComponentEvent;
039import java.awt.event.ComponentListener;
040import java.net.URL;
041import java.rmi.RemoteException;
042
043import javax.swing.*;
044
045import ucar.unidata.data.DataChoice;
046import ucar.unidata.data.DataSelection;
047import ucar.unidata.data.DataSourceImpl;
048import ucar.unidata.data.DataSelectionComponent;
049import ucar.unidata.data.GeoSelection;
050import ucar.unidata.data.grid.GridUtil;
051import ucar.unidata.idv.IdvObjectStore;
052import ucar.unidata.idv.MapViewManager;
053import ucar.unidata.util.Range;
054import ucar.unidata.view.geoloc.MapProjectionDisplay;
055import ucar.unidata.view.geoloc.MapProjectionDisplayJ3D;
056import ucar.visad.display.DisplayMaster;
057import ucar.visad.display.MapLines;
058
059import visad.*;
060import visad.data.mcidas.AREACoordinateSystem;
061import visad.data.mcidas.BaseMapAdapter;
062import ucar.visad.display.Displayable;
063import ucar.visad.display.LineDrawing;
064import visad.georef.MapProjection;
065import org.slf4j.Logger;
066import org.slf4j.LoggerFactory;
067
068
069public 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}