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 }