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