001 /*
002 * $Id: PolarOrbitTrackControl.java,v 1.42 2012/02/19 17:35:38 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.control;
032
033 import edu.wisc.ssec.mcidasv.McIdasPreferenceManager;
034
035 import edu.wisc.ssec.mcidasv.data.GroundStations;
036 import edu.wisc.ssec.mcidasv.data.PolarOrbitTrackDataSource;
037 import edu.wisc.ssec.mcidasv.data.adde.sgp4.AstroConst;
038 import edu.wisc.ssec.mcidasv.data.hydra.CurveDrawer;
039 import edu.wisc.ssec.mcidasv.util.XmlUtil;
040
041 import java.awt.BorderLayout;
042 import java.awt.Color;
043 import java.awt.Component;
044 import java.awt.Container;
045 import java.awt.Dimension;
046 import java.awt.FlowLayout;
047 import java.awt.Insets;
048 import java.awt.event.ActionEvent;
049 import java.awt.event.ActionListener;
050 import java.awt.event.FocusEvent;
051 import java.awt.event.FocusListener;
052 import java.awt.event.KeyEvent;
053 import java.awt.event.KeyListener;
054 import java.lang.Math;
055 import java.rmi.RemoteException;
056 import java.util.ArrayList;
057 import java.util.List;
058
059 import javax.swing.Box;
060 import javax.swing.BoxLayout;
061 import javax.swing.JButton;
062 import javax.swing.JComboBox;
063 import javax.swing.JComponent;
064 import javax.swing.JLabel;
065 import javax.swing.JPanel;
066 import javax.swing.JSlider;
067 import javax.swing.JTextField;
068
069 import org.slf4j.Logger;
070 import org.slf4j.LoggerFactory;
071 import org.w3c.dom.Element;
072 import org.w3c.dom.NodeList;
073
074 import ucar.unidata.data.DataChoice;
075 import ucar.unidata.data.DataInstance;
076 import ucar.unidata.data.DataSourceImpl;
077 import ucar.unidata.idv.control.DisplayControlImpl;
078 import ucar.unidata.ui.LatLonWidget;
079 import ucar.unidata.util.GuiUtils;
080 import ucar.unidata.util.GuiUtils.ColorSwatch;
081 import ucar.unidata.util.IOUtil;
082 import ucar.unidata.view.geoloc.NavigatedDisplay;
083 import ucar.visad.display.CompositeDisplayable;
084 import ucar.visad.display.Displayable;
085 import ucar.visad.display.DisplayableData;
086 import ucar.visad.display.TextDisplayable;
087
088 import visad.Data;
089 import visad.DisplayRealType;
090 import visad.Gridded2DSet;
091 import visad.MathType;
092 import visad.RealTuple;
093 import visad.RealTupleType;
094 import visad.SampledSet;
095 import visad.Text;
096 import visad.TextControl;
097 import visad.TextControl.Justification;
098 import visad.TextType;
099 import visad.Tuple;
100 import visad.TupleType;
101 import visad.UnionSet;
102 import visad.VisADException;
103 import visad.georef.EarthLocation;
104 import visad.georef.EarthLocationTuple;
105 import visad.georef.LatLonPoint;
106 import visad.georef.LatLonTuple;
107
108 /**
109 * {@link ucar.unidata.idv.control.PolarOrbitTrackControl} with some McIDAS-V
110 * specific extensions. Namely parameter sets and support for inverted
111 * parameter defaults.
112 */
113 public class PolarOrbitTrackControl extends DisplayControlImpl {
114
115 private static final Logger logger = LoggerFactory.getLogger(PolarOrbitTrackControl.class);
116
117 /** The spacing used in the grid layout */
118 protected static final int GRID_SPACING = 3;
119
120 /** Used by derived classes when they do a GuiUtils.doLayout */
121 protected static final Insets GRID_INSETS = new Insets(GRID_SPACING,
122 GRID_SPACING,
123 GRID_SPACING,
124 GRID_SPACING);
125 private JLabel satelliteName = new JLabel(" ");;
126 private static final JLabel kmLabel = new JLabel(" km");
127 private JTextField swathWidthFld = new JTextField(" ", 5);
128 private JPanel swathWidthPanel;
129 private JButton saveBtn;
130
131 /**
132 * position slider
133 */
134 private double latitude;
135 private double longitude;
136 private double altitude;
137 private JPanel fontSizePanel;
138 private JPanel colorPanel;
139 private JPanel antColorPanel;
140 private JPanel locationPanel;
141 private JPanel latLonAltPanel;
142
143 private int locationIndex = -1;
144 private List stations;
145 private List lats;
146 private List lons;
147 private List alts;
148
149 /** Property name to get the list or urls */
150 public final String PREF_GROUNDSTATIONS = "mcv.groundstations";
151
152 private JComboBox locationComboBox;
153 private JTextField locationEditor;
154
155 private String station = "";
156 private TextDisplayable groundStationDsp;
157
158 private static final int defaultAntAngle = 5;
159 private int angle = defaultAntAngle;
160
161 private DataChoice dataChoice;
162
163 /** Input for lat/lon center point */
164 protected LatLonWidget latLonWidget = new LatLonWidget();
165
166 private JTextField latFld;
167 private JTextField lonFld;
168 private JTextField altitudeFld = new JTextField(" ", 5);
169 private JTextField antennaAngle = new JTextField(" 5", 5);
170
171 private ActionListener fontSizeChange;
172 private FocusListener fontSizeFocusChange;
173
174 /** Font size control */
175 private static final int SLIDER_MAX = 10;
176 private static final int SLIDER_MIN = 1;
177 private static final int SLIDER_WIDTH = 150;
178 private static final int SLIDER_HEIGHT = 16;
179
180 private JSlider fontSizeSlider;
181 private JTextField fontSizeFld = new JTextField();
182
183 private DisplayableData trackDisplay;
184 private CompositeDisplayable trackDsp;
185 private CompositeDisplayable swathDsp;
186 private CompositeDisplayable circleDsp;
187 private TupleType tupleType;
188
189 private int fontSize;
190 private int defaultSize = 3;
191 private ColorSwatch colorSwatch;
192 private Color color;
193 private Color defaultColor = Color.GREEN;
194 private ColorSwatch antColorSwatch;
195 private Color antColor;
196 private Color defaultAntColor = Color.WHITE;
197 private PolarOrbitTrackDataSource dataSource;
198
199 private CurveDrawer coverageCircle;
200 private double satelliteAltitude = 0.0;
201
202 private double centerAlt = 0.0;
203 private double centerLat = 0.0;
204 private double centerLon = 0.0;
205 private double satZ = 0.0;
206 private int dTime;
207 private NavigatedDisplay navDsp = null;
208 private TextType textType = null;
209 private double width = 0.0;
210
211 /** Path to the McV swathwidths.xml */
212 private static final String SWATH_WIDTHS = "/edu/wisc/ssec/mcidasv/resources/swathwidths.xml";
213 private static final String TAG_SATELLITE = "satellite";
214 private static final String ATTR_NAME = "name";
215 private static final String ATTR_WIDTH = "width";
216 private Element root = null;
217
218 public PolarOrbitTrackControl() {
219 super();
220 logger.trace("created new tlecontrol={}", Integer.toHexString(hashCode()));
221 setAttributeFlags(FLAG_COLORTABLE);
222 try {
223 final String xml =
224 IOUtil.readContents(SWATH_WIDTHS, McIdasPreferenceManager.class);
225 root = XmlUtil.getRoot(xml);
226 } catch (Exception e) {
227 System.out.println("problem reading swathwidths.xml e=" + e);
228 }
229 }
230
231 @Override public boolean init(DataChoice dataChoice)
232 throws VisADException, RemoteException
233 {
234 this.dataChoice = dataChoice;
235 String choiceName = dataChoice.getName();
236 NodeList nodeList = root.getElementsByTagName(TAG_SATELLITE);
237 int num = nodeList.getLength();
238 if (num > 0) {
239 for (int i=0; i<num; i++) {
240 Element n =(Element)(nodeList.item(i));
241 String satName = n.getAttribute(ATTR_NAME);
242 if (satName.equals(choiceName)) {
243 String strWidth = n.getAttribute(ATTR_WIDTH);
244 if (strWidth.isEmpty()) strWidth = "0";
245 Double dWidth = new Double(strWidth);
246 this.width = dWidth.doubleValue();
247 break;
248 }
249 }
250 }
251 try {
252 trackDsp = new CompositeDisplayable();
253 swathDsp = new CompositeDisplayable();
254 circleDsp = new CompositeDisplayable();
255 } catch (Exception e) {
256 System.out.println("problem creating composite displayable e=" + e);
257 return false;
258 }
259 boolean result = super.init((DataChoice)this.getDataChoices().get(0));
260
261 this.tupleType = makeTupleType();
262
263 Data data = getData(getDataInstance());
264 createTrackDisplay(data, true);
265 this.dataSource = getDataSource();
266 try {
267 navDsp = getNavigatedDisplay();
268 EarthLocation earthLoc = navDsp.getCenterPoint();
269 LatLonPoint llp = earthLoc.getLatLonPoint();
270 centerLat = llp.getLatitude().getValue();
271 centerLon = llp.getLongitude().getValue();
272 centerAlt = dataSource.getNearestAltToGroundStation(centerLat, centerLon)/1000.0;
273 EarthLocationTuple elt = new EarthLocationTuple(centerLat, centerLon, centerAlt);
274 double[] xyz = navDsp.getSpatialCoordinates((EarthLocation)elt).getValues();
275 satZ = xyz[2]/5.0;
276 applyTrackPosition();
277 } catch (Exception e) {
278 System.out.println("get display center e=" + e);
279 }
280
281 return result;
282 }
283
284 private void createTrackDisplay(Data data, boolean doTrack) {
285 try {
286 this.fontSize = getFontSize();
287 this.color = getColor();
288 List<String> dts = new ArrayList();
289 if (data instanceof Tuple) {
290 Data[] dataArr = ((Tuple)data).getComponents();
291
292 int npts = dataArr.length;
293 float[][] latlon = new float[2][npts];
294 float fSize = this.fontSize/10.f;
295
296 for (int i=0; i<npts; i++) {
297 Tuple t = (Tuple)dataArr[i];
298 Data[] tupleComps = t.getComponents();
299
300 LatLonTuple llt = (LatLonTuple)tupleComps[1];
301 double dlat = llt.getLatitude().getValue();
302 double dlon = llt.getLongitude().getValue();
303
304 if (doTrack) {
305 String str = ((Text)tupleComps[0]).getValue();
306 dts.add(str);
307 int indx = str.indexOf(" ") + 1;
308 String subStr = "- " + str.substring(indx, indx+5);
309 TextDisplayable time = new TextDisplayable(getTextType());
310 time.setJustification(TextControl.Justification.LEFT);
311 time.setVerticalJustification(TextControl.Justification.CENTER);
312 time.setColor(this.color);
313
314 RealTuple lonLat =
315 new RealTuple(RealTupleType.SpatialEarth2DTuple,
316 new double[] { dlon, dlat });
317 if ((i % 5) == 0) {
318 Tuple tup = new Tuple(getTupleType(),
319 new Data[] { lonLat, new Text(getTextType(), subStr)});
320 time.setData(tup);
321 this.trackDsp.addDisplayable(time);
322 }
323 }
324 float lat = (float)dlat;
325 float lon = (float)dlon;
326 latlon[0][i] = lat;
327 latlon[1][i] = lon;
328 }
329
330 if (doTrack) {
331 setDisplayableTextSize(this.fontSize);
332 Gridded2DSet track = new Gridded2DSet(RealTupleType.LatitudeLongitudeTuple,
333 latlon, npts);
334 SampledSet[] set = new SampledSet[1];
335 set[0] = track;
336 UnionSet uset = new UnionSet(set);
337 CurveDrawer trackLines = new CurveDrawer(uset);
338 trackLines.setData(uset);
339 this.trackDsp.addDisplayable(trackLines);
340 trackLines.setDrawingEnabled(false);
341 this.trackDisplay = trackLines;
342
343 this.trackDsp.setColor(this.color);
344 this.trackDsp.setLineWidth(2.0f);
345
346 addDisplayable(this.trackDsp, FLAG_COLORTABLE);
347 }
348
349 float[][][] crv = getSwath(latlon);
350 int npt = crv[0][0].length;
351 float[][] leftC = new float[2][npt];
352 float[][] rightC = new float[2][npt];
353 for (int i=0; i<npt; i++) {
354 leftC[0][i] = crv[0][0][i];
355 leftC[1][i] = crv[0][1][i];
356 rightC[0][i] = crv[1][0][i];
357 rightC[1][i] = crv[1][1][i];
358 }
359 Gridded2DSet left = new Gridded2DSet(RealTupleType.LatitudeLongitudeTuple,
360 leftC, npt);
361 SampledSet[] lSet = new SampledSet[1];
362 lSet[0] = left;
363 UnionSet lUSet = new UnionSet(lSet);
364 CurveDrawer leftLines = new CurveDrawer(lUSet);
365 leftLines.setLineStyle(1);
366 leftLines.setData(lUSet);
367 swathDsp.addDisplayable(leftLines);
368 leftLines.setDrawingEnabled(false);
369
370 Gridded2DSet right = new Gridded2DSet(RealTupleType.LatitudeLongitudeTuple,
371 rightC, npt);
372 SampledSet[] rSet = new SampledSet[1];
373 rSet[0] = right;
374 UnionSet rUSet = new UnionSet(rSet);
375 CurveDrawer rightLines = new CurveDrawer(rUSet);
376 rightLines.setLineStyle(1);
377 rightLines.setData(rUSet);
378 this.swathDsp.addDisplayable(rightLines);
379 rightLines.setDrawingEnabled(false);
380
381 this.swathDsp.setColor(this.color);
382 this.swathDsp.setLineWidth(1.0f);
383 addDisplayable(this.swathDsp, FLAG_COLORTABLE);
384 }
385 } catch (Exception e) {
386 System.out.println("getData e=" + e);
387 }
388 return;
389 }
390
391 private float[][][] getSwath(float[][] track) {
392 double earthRadius = AstroConst.R_Earth_mean/1000.0;
393 int npt = track[0].length-1;
394 int l2 = track.length;
395 float[][][] ret = new float[2][2][npt-1];
396 float zero = (float)0.0;
397 try {
398 int indx = 0;
399 for (int i=1; i<npt; i++) {
400 double latA = Math.toRadians(track[0][i-1]);
401 double lonA = Math.toRadians(track[1][i-1]);
402
403 double latB = Math.toRadians(track[0][i+1]);
404 double lonB = Math.toRadians(track[1][i+1]);
405
406 double diffLon = lonB - lonA;
407 double bX = Math.cos(latB) * Math.cos(diffLon);
408 double bY = Math.cos(latB) * Math.sin(diffLon);
409 double xFac = Math.cos(latA)+bX;
410 double latC = Math.atan2(Math.sin(latA)+Math.sin(latB), Math.sqrt(xFac*xFac + bY*bY));
411 double lonC = lonA + Math.atan2(bY, xFac);
412
413 double bearing = Math.atan2(Math.sin(diffLon)*Math.cos(latB),
414 Math.cos(latA)*Math.sin(latB)-Math.sin(latA)*Math.cos(latB)*Math.cos(diffLon))
415 + Math.PI/2.0;
416 double dist = this.width/2.0;
417 dist /= earthRadius;
418 double lat = Math.asin(Math.sin(latC)*Math.cos(dist) +
419 Math.cos(latC)*Math.sin(dist)*Math.cos(bearing));
420 double lon = lonC + Math.atan2(Math.sin(bearing)*Math.sin(dist)*Math.cos(latC),
421 Math.cos(dist)-Math.sin(latC)*Math.sin(lat));
422 float latD = (float)Math.toDegrees(lat);
423 float lonD = (float)Math.toDegrees(lon);
424
425 bearing += Math.PI;
426 lat = Math.asin(Math.sin(latC)*Math.cos(dist) +
427 Math.cos(latC)*Math.sin(dist)*Math.cos(bearing));
428 lon = lonC + Math.atan2(Math.sin(bearing)*Math.sin(dist)*Math.cos(latC),
429 Math.cos(dist)-Math.sin(latC)*Math.sin(lat));
430 float latE = (float)Math.toDegrees(lat);
431 float lonE = (float)Math.toDegrees(lon);
432
433 ret[0][0][indx] = latD;
434 ret[0][1][indx] = lonD;
435
436 ret[1][0][indx] = latE;
437 ret[1][1][indx] = lonE;
438 ++indx;
439 }
440 } catch (Exception e) {
441 System.out.println("e=" + e);
442 return null;
443 }
444 return ret;
445 }
446
447 private TupleType makeTupleType() {
448 TupleType t = null;
449 try {
450 t = new TupleType(new MathType[] {RealTupleType.SpatialEarth2DTuple,
451 getTextType()});
452 } catch (Exception e) {
453 System.out.println("\nPolarOrbitTrackControl.makeTupleType e=" + e);
454 System.out.println(" textType=" + getTextType());
455 }
456 return t;
457 }
458
459 public JComponent makeColorBox(Color swatchColor) {
460 GuiUtils.ColorSwatch swatch = new GuiUtils.ColorSwatch(swatchColor,
461 "Color") {
462 public void userSelectedNewColor(Color c) {
463 try {
464 getIdv().showWaitCursor();
465 setColor(c);
466 setBackground(c);
467 getIdv().showNormalCursor();
468 } catch (Exception e) {
469 System.out.println("\nsetColor e=" + e);
470 setColor(defaultColor);
471 }
472 }
473 };
474 return swatch;
475 }
476
477 public JComponent makeAntColorBox(Color swatchAntColor) {
478 GuiUtils.ColorSwatch swatch = new GuiUtils.ColorSwatch(swatchAntColor,
479 "Color") {
480 public void userSelectedNewColor(Color c) {
481 try {
482 getIdv().showWaitCursor();
483 setAntColor(c);
484 setBackground(c);
485 getIdv().showNormalCursor();
486 } catch (Exception e) {
487 System.out.println("\nsetAntColor e=" + e);
488 setAntColor(defaultAntColor);
489 }
490 }
491 };
492 return swatch;
493 }
494
495 /**
496 * Called by doMakeWindow in DisplayControlImpl, which then calls its
497 * doMakeMainButtonPanel(), which makes more buttons.
498 *
499 * @return container of contents
500 */
501
502 public Container doMakeContents() {
503 this.fontSizeChange =new ActionListener() {
504 public void actionPerformed(ActionEvent ae) {
505 String str = fontSizeFld.getText();
506 int size = new Integer(str).intValue();
507 moveFontSizeSlider(size);
508 setDisplayableTextSize(size);
509 }
510 };
511 this.fontSizeFocusChange = new FocusListener() {
512 public void focusGained(FocusEvent fe) {
513 }
514 public void focusLost(FocusEvent fe) {
515 String str = fontSizeFld.getText();
516 int size = new Integer(str).intValue();
517 moveFontSizeSlider(size);
518 setDisplayableTextSize(size);
519 }
520 };
521
522 this.fontSizeSlider = GuiUtils.makeSlider(SLIDER_MIN, SLIDER_MAX, defaultSize,
523 this, "sliderChanged", true);
524 this.fontSizeSlider.setPreferredSize(new Dimension(SLIDER_WIDTH,SLIDER_HEIGHT));
525 this.fontSizeSlider.setMajorTickSpacing(1);
526 this.fontSizeSlider.setSnapToTicks(true);
527 int size = getSizeValue(this.fontSizeSlider);
528 setFontSize(size);
529 this.fontSizeFld = new JTextField(Integer.toString(size),3);
530 this.fontSizeFld.addFocusListener(this.fontSizeFocusChange);
531 this.fontSizeFld.addActionListener(this.fontSizeChange);
532
533 fontSizePanel = new JPanel();
534 fontSizePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
535 fontSizePanel.add(new JLabel("Font Size: "));
536 fontSizePanel.add(fontSizeFld);
537 fontSizePanel.add(fontSizeSlider);
538
539 Color swatchColor = getColor();
540 colorSwatch = (GuiUtils.ColorSwatch)makeColorBox(swatchColor);
541
542 colorPanel = new JPanel();
543 colorPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
544 colorPanel.add(new JLabel("Set Color: "));
545 colorPanel.add(colorSwatch);
546
547 JPanel groundStationPanel = makeGroundStationPanel();
548
549 Insets dfltGridSpacing = new Insets(4, 0, 4, 0);
550 String dfltLblSpacing = " ";
551
552 swathWidthPanel = makeSwathWidthPanel();
553
554 JPanel outerPanel = new JPanel(new BorderLayout());
555
556 JPanel mainPanel = new JPanel();
557 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
558 mainPanel.add(swathWidthPanel);
559 mainPanel.add(fontSizePanel);
560 mainPanel.add(colorPanel);
561 mainPanel.add(locationPanel);
562 mainPanel.add(groundStationPanel);
563 mainPanel.add(latLonAltPanel);
564 mainPanel.add(antColorPanel);
565
566 outerPanel.add(mainPanel, BorderLayout.NORTH);
567
568 return outerPanel;
569 }
570
571 private JPanel makeGroundStationPanel() {
572 locationComboBox = new JComboBox();
573 locationComboBox.setEditable(true);
574 locationEditor = (JTextField)locationComboBox.getEditor().getEditorComponent();
575 locationEditor.addKeyListener(new KeyListener() {
576 public void keyPressed(KeyEvent e) {}
577 public void keyReleased(KeyEvent e) {}
578 public void keyTyped(KeyEvent e) {
579 locationIndex = -1;
580 }
581 });
582
583 GroundStations gs = new GroundStations(null);
584 stations = gs.getStations();
585 GuiUtils.setListData(locationComboBox, stations);
586 lats = gs.getLatitudes();
587 lons = gs.getLongitudes();
588 alts = gs.getAltitudes();
589
590 locationComboBox.addActionListener(new ActionListener() {
591 public void actionPerformed(ActionEvent ae) {
592 setStation((String)locationComboBox.getSelectedItem());
593 locationIndex = locationComboBox.getSelectedIndex();
594 if (locationIndex < 0) {
595 try {
596 Object stat = (Object)getStation();
597 if (stations.contains(stat)) {
598 locationIndex = stations.indexOf(stat);
599 locationComboBox.setSelectedIndex(locationIndex);
600 }
601 } catch (Exception e) {
602 }
603 } else {
604 try {
605 String str = (String)(lats.get(locationIndex));
606 Double d = new Double(str);
607 double dVal = d.doubleValue();
608 latLonWidget.setLat(dVal);
609 setLatitude();
610 str = (String)(lons.get(locationIndex));
611 d = new Double(str);
612 dVal = d.doubleValue();
613 latLonWidget.setLon(dVal);
614 setLongitude();
615 str = (String)(alts.get(locationIndex));
616 altitudeFld.setText(str);
617 setAltitude();
618 int val = getAntennaAngle();
619 setAntennaAngle(val);
620 } catch (Exception e) {
621 }
622 }
623 setSatelliteAltitude(dataSource.getNearestAltToGroundStation(latitude, longitude)/1000.0);
624 dTime = dataSource.getDTime();
625 redrawCoverageCircle();
626 }
627 });
628
629 latFld = latLonWidget.getLatField();
630 lonFld = latLonWidget.getLonField();
631 String str = (String)(alts.get(0));
632 altitudeFld = new JTextField(str, 5);
633 str = (String)(lats.get(0));
634 Double d;
635 double dVal;
636 if (!str.equals(" ")) {
637 d = new Double(str);
638 dVal = d.doubleValue();
639 latLonWidget.setLat(dVal);
640 }
641 if (!str.equals(" ")) {
642 str = (String)(lons.get(0));
643 d = new Double(str);
644 dVal = d.doubleValue();
645 latLonWidget.setLon(dVal);
646 }
647
648 ActionListener latLonListener = new ActionListener() {
649 public void actionPerformed(ActionEvent ae) {
650 setLatitude();
651 setLongitude();
652 setAltitude();
653 redrawCoverageCircle();
654 }
655 };
656 FocusListener latLonFocusChange = new FocusListener() {
657 public void focusGained(FocusEvent fe) {
658 latFld.setCaretPosition(latFld.getText().length());
659 lonFld.setCaretPosition(lonFld.getText().length());
660 }
661 public void focusLost(FocusEvent fe) {
662 setLatitude();
663 setLongitude();
664 setAltitude();
665 redrawCoverageCircle();
666 }
667 };
668 latFld.addActionListener(latLonListener);
669 lonFld.addActionListener(latLonListener);
670 latFld.addFocusListener(latLonFocusChange);
671 lonFld.addFocusListener(latLonFocusChange);
672 antennaAngle.addActionListener(new ActionListener() {
673 public void actionPerformed(ActionEvent ae) {
674 String str = antennaAngle.getText();
675 Integer iVal = new Integer(str.trim());
676 int val = iVal.intValue();
677 setAntennaAngle(val);
678 redrawCoverageCircle();
679 }
680 });
681 antennaAngle.addFocusListener(new FocusListener() {
682 public void focusGained(FocusEvent fe) {
683 }
684 public void focusLost(FocusEvent fe) {
685 String str = antennaAngle.getText();
686 Integer iVal = new Integer(str.trim());
687 int val = iVal.intValue();
688 setAntennaAngle(val);
689 redrawCoverageCircle();
690 }
691 });
692
693 locationPanel = new JPanel();
694 locationPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
695 locationPanel.add(new JLabel("Ground Station:"));
696 locationPanel.add(locationComboBox);
697
698 latLonAltPanel = new JPanel();
699 latLonAltPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
700 latLonAltPanel.add(latLonWidget);
701 latLonAltPanel.add(new JLabel("Altitude: "));
702 latLonAltPanel.add(altitudeFld);
703 latLonAltPanel.add(new JLabel("Antenna Angle: "));
704 latLonAltPanel.add(antennaAngle);
705
706 Color swatchAntColor = getAntColor();
707 antColorSwatch = (GuiUtils.ColorSwatch)makeAntColorBox(swatchAntColor);
708
709 antColorPanel = new JPanel();
710 antColorPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
711 antColorPanel.add(new JLabel("Set Color: "));
712 antColorPanel.add(antColorSwatch);
713
714 return latLonAltPanel;
715 }
716
717 private JPanel makeSwathWidthPanel() {
718 if (this.dataChoice != null)
719 satelliteName = new JLabel(this.dataChoice.getName());
720 Double dWidth = new Double(this.width);
721 swathWidthFld = new JTextField(dWidth.toString(), 6);
722 swathWidthFld.setHorizontalAlignment(JTextField.CENTER);
723 swathWidthFld.addActionListener(new ActionListener() {
724 public void actionPerformed(ActionEvent ae) {
725 changeSwathWidth();
726 }
727 });
728 swathWidthFld.addFocusListener(new FocusListener() {
729 public void focusGained(FocusEvent fe) {
730 }
731 public void focusLost(FocusEvent fe) {
732 changeSwathWidth();
733 }
734 });
735
736 saveBtn = new JButton("Save");
737
738 JPanel jp = new JPanel(new FlowLayout(FlowLayout.LEFT));
739 jp.add(new JLabel("Satellite: "));
740 jp.add(satelliteName);
741 jp.add(Box.createHorizontalStrut(5));
742 jp.add(new JLabel("Swath Width: "));
743 jp.add(swathWidthFld);
744 jp.add(kmLabel);
745 jp.add(Box.createHorizontalStrut(5));
746 jp.add(saveBtn);
747
748 return jp;
749 }
750
751 private void changeSwathWidth() {
752 String str = swathWidthFld.getText();
753 Double dVal = new Double(str.trim());
754 double val = dVal.doubleValue();
755 setSwathWidth(val);
756 try {
757 removeDisplayable(swathDsp);
758 Data data = getData(getDataInstance());
759 swathDsp = new CompositeDisplayable();
760 createTrackDisplay(data, false);
761 } catch (Exception e) {
762 System.out.println("\nproblem redrawing swaths e=" + e);
763 }
764 }
765
766 private void setSwathWidth(double val) {
767 this.width = val;
768 }
769
770 /**
771 * Apply the map (height) position to the displays
772 */
773
774 private void applyTrackPosition() {
775 try {
776 DisplayRealType dispType = navDsp.getDisplayAltitudeType();
777 trackDsp.setConstantPosition(this.satZ, dispType);
778 } catch (Exception exc) {
779 System.out.println("Setting track z-position exc=" + exc);
780 }
781 }
782
783 private void redrawCoverageCircle() {
784 try {
785
786 int num = circleDsp.displayableCount();
787 for (int i=0; i<num; i++) {
788 circleDsp.removeDisplayable(0);
789 }
790
791 if (drawCoverageCircle(Math.toRadians(this.latitude), Math.toRadians(this.longitude),
792 this.satelliteAltitude, getAntColor()) != null) {
793 drawGroundStation();
794 circleDsp.setColor(getAntColor());
795 circleDsp.setLineWidth(1f);
796 circleDsp.addDisplayable(this.coverageCircle);
797 circleDsp.addDisplayable(this.groundStationDsp);
798 addDisplayable(circleDsp, FLAG_COLORTABLE);
799 }
800 } catch (Exception e) {
801 System.out.println("redrawCoverageCircle e=" + e);
802 }
803 }
804
805 private CurveDrawer drawCoverageCircle(double lat, double lon, double satAlt, Color color) {
806 if (!(latLonWidget.isLatLonDefined())) return null;
807 /* mean earthRadius in km */
808 double earthRadius = AstroConst.R_Earth_mean/1000.0;
809 satAlt += earthRadius;
810 double pi = Math.PI;
811 double SAC = pi/2.0 + Math.toRadians(getAntennaAngle());
812 double sinASC = earthRadius * Math.sin(SAC) / satAlt;
813 double dist = earthRadius * (Math.PI - SAC - Math.asin(sinASC));
814 double rat = dist/earthRadius;
815
816 int npts = 360;
817 float[][] latlon = new float[2][npts];
818 double cosDist = Math.cos(rat);
819 double sinDist = Math.sin(rat);
820 double sinLat = Math.sin(lat);
821 double cosLat = Math.cos(lat);
822 double sinLon = -Math.sin(lon);
823 double cosLon = Math.cos(lon);
824 for (int i=0; i<npts; i++) {
825 double azimuth = Math.toRadians((double)i);
826 double cosBear = Math.cos(azimuth);
827 double sinBear = Math.sin(azimuth);
828 double z = cosDist * sinLat +
829 sinDist * cosLat * cosBear;
830 double y = cosLat * cosLon * cosDist +
831 sinDist * (sinLon*sinBear - sinLat*cosLon*cosBear);
832 double x = cosLat * sinLon * cosDist -
833 sinDist * (cosLon*sinBear + sinLat*sinLon*cosBear);
834 double r = Math.sqrt(x*x + y*y);
835 double latRad = Math.atan2(z, r);
836 double lonRad = 0.0;
837 if (r > 0.0) lonRad = -Math.atan2(x, y);
838 latlon[0][i] = (float)Math.toDegrees(latRad);
839 latlon[1][i] = (float)Math.toDegrees(lonRad);
840 }
841 try {
842 Gridded2DSet circle = new Gridded2DSet(RealTupleType.LatitudeLongitudeTuple,
843 latlon, npts);
844 SampledSet[] set = new SampledSet[1];
845 set[0] = circle;
846 UnionSet uset = new UnionSet(set);
847 this.coverageCircle = new CurveDrawer(uset);
848 this.coverageCircle.setLineStyle(1);
849 this.coverageCircle.setColor(getAntColor());
850 this.coverageCircle.setData(uset);
851 this.coverageCircle.setDrawingEnabled(false);
852 } catch (Exception e) {
853 System.out.println("drawCoverageCircle e=" + e);
854 return null;
855 }
856 return this.coverageCircle;
857 }
858
859 private int getSizeValue(JSlider slider) {
860 int value = slider.getValue();
861 if (value < SLIDER_MIN) {
862 value = SLIDER_MIN;
863 } else if (value > SLIDER_MAX) {
864 value = SLIDER_MAX;
865 }
866 return value;
867 }
868
869 public int getFontSize() {
870 if (this.fontSize < 1) this.fontSize = defaultSize;
871 return this.fontSize;
872 }
873
874 public void setFontSizeTextField(int size) {
875 size = setFontSize(size);
876 try {
877 if (this.fontSizeFld != null) {
878 this.fontSizeFld.setText(new Integer(size).toString());
879 }
880 } catch (Exception e) {
881 System.out.println("Exception in PolarOrbitTrackControl.setFontSizeTextField e=" + e);
882 }
883 }
884
885 private void moveFontSizeSlider(int size) {
886 size = setFontSize(size);
887 try {
888 if (this.fontSizeSlider != null) {
889 this.fontSizeSlider.setValue(size);
890 }
891 } catch (Exception e) {
892 System.out.println("Exception in PolarOrbitTrackControl.moveFontSizeSlider e=" + e);
893 }
894 }
895
896 private void setDisplayableTextSize(int size) {
897 size = setFontSize(size);
898 try {
899 float fSize = (float)size/10.0f;
900 int num = this.trackDsp.displayableCount()-1;
901 TextDisplayable textDsp = null;
902 for (int i=num; i>-1; i--) {
903 Displayable dsp = this.trackDsp.getDisplayable(i);
904 if (dsp instanceof TextDisplayable) {
905 textDsp = (TextDisplayable)dsp;
906 break;
907 }
908 }
909 if (textDsp != null) {
910 textDsp.setTextSize(fSize);
911 }
912 } catch (Exception e) {
913 System.out.println("Exception in PolarOrbitTrackControl.setDisplayableTextSize e=" + e);
914 }
915 }
916
917 public int setFontSize(int size) {
918 if (size < 1) size = defaultSize;
919 this.fontSize = size;
920 return this.fontSize;
921 }
922
923 public Color getColor() {
924 if (this.color == null) this.color = defaultColor;
925 return this.color;
926 }
927
928 public void setColor(Color color) {
929 if (this.color == null) this.color = defaultColor;
930 try {
931 this.trackDsp.setColor(color);
932 this.swathDsp.setColor(color);
933 this.color = color;
934 } catch (Exception e) {
935 System.out.println("Exception in PolarOrbitTrackControl.setColor e=" + e);
936 }
937 }
938
939 public Color getAntColor() {
940 if (this.antColor == null) this.antColor = defaultAntColor;
941 return this.antColor;
942 }
943
944 public void setAntColor(Color color) {
945 if (color == null) color = defaultAntColor;
946 try {
947 this.antColor = color;
948 circleDsp.setColor(color);
949 } catch (Exception e) {
950 System.out.println("Exception in PolarOrbitTrackControl.setAntColor e=" + e);
951 }
952 }
953
954 public void setLatitude() {
955 this.latitude = latLonWidget.getLat();
956 }
957
958 public double getLatitude() {
959 return this.latitude;
960 }
961
962 public void setLongitude() {
963 this.longitude = latLonWidget.getLon();
964 }
965
966 public double getLongitude() {
967 return this.longitude;
968 }
969
970 public void setAltitude() {
971 String str = altitudeFld.getText();
972 try {
973 Double d = new Double(str);
974 this.altitude = d.doubleValue();
975 } catch (Exception e) {
976 this.altitude = 0.0;
977 }
978 }
979
980 public void sliderChanged(int sliderValue) {
981 setFontSizeTextField(sliderValue);
982 setDisplayableTextSize(sliderValue);
983 }
984
985 public void setStation(String val) {
986 this.station = val.trim();
987 }
988
989 public String getStation() {
990 return this.station;
991 }
992
993 public void setAntennaAngle(int val) {
994 String str = " " + val;
995 antennaAngle.setText(str);
996 this.angle = val;
997 }
998
999 public int getAntennaAngle() {
1000 String str = antennaAngle.getText();
1001 this.angle = new Integer(str.trim()).intValue();
1002 if (this.angle < defaultAntAngle) this.angle = defaultAntAngle;
1003 return this.angle;
1004 }
1005
1006 private void setSatelliteAltitude(double val) {
1007 this.satelliteAltitude = val;
1008 }
1009
1010 private void drawGroundStation() {
1011 try {
1012 String str = "+" + getStation();
1013 this.groundStationDsp = new TextDisplayable(getTextType());
1014 this.groundStationDsp.setJustification(TextControl.Justification.LEFT);
1015 this.groundStationDsp.setVerticalJustification(TextControl.Justification.CENTER);
1016 float tSize = (float)getFontSize()/10.0f;
1017 this.groundStationDsp.setTextSize(tSize);
1018 this.groundStationDsp.setColor(getAntColor());
1019
1020 double dlat = getLatitude();
1021 double dlon = getLongitude();
1022 RealTuple lonLat =
1023 new RealTuple(RealTupleType.SpatialEarth2DTuple,
1024 new double[] { dlon, dlat });
1025 Tuple tup = new Tuple(getTupleType(),
1026 new Data[] { lonLat, new Text(getTextType(), str)});
1027 this.groundStationDsp.setData(tup);
1028 } catch (Exception e) {
1029 System.out.println("drawGroundStation e=" + e);
1030 }
1031 }
1032
1033 public PolarOrbitTrackDataSource getDataSource() {
1034 DataSourceImpl ds = null;
1035 List dataSources = getDataSources();
1036 boolean gotit = false;
1037 if (!dataSources.isEmpty()) {
1038 int nsrc = dataSources.size();
1039 for (int i=0; i<nsrc; i++) {
1040 ds = (DataSourceImpl)dataSources.get(nsrc-i-1);
1041 if (ds instanceof PolarOrbitTrackDataSource) {
1042 gotit = true;
1043 break;
1044 }
1045 }
1046 }
1047 if (!gotit) return null;
1048 return (PolarOrbitTrackDataSource)ds;
1049 }
1050
1051 private TextType getTextType() {
1052 if (this.textType == null) {
1053 String dispName = getDisplayName();
1054 setDisplayName(getLongParamName() + " " + dispName);
1055 try {
1056 String longName = getLongParamName().replaceAll(" ", "");
1057 this.textType = new TextType(longName);
1058 } catch (Exception e) {
1059 this.textType = TextType.Generic;
1060 }
1061 }
1062 return this.textType;
1063 }
1064
1065 private TupleType getTupleType() {
1066 return this.tupleType;
1067 }
1068 }