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    }