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