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 }