001/*
002 * $Id: SatelliteTleSGP4.java,v 1.3 2011/03/24 16:06:33 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
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
031package edu.wisc.ssec.mcidasv.data.adde.sgp4;
032/*
033import gov.nasa.worldwind.geom.Angle;
034import gov.nasa.worldwind.geom.Position;
035import java.awt.Color;
036import java.util.Random;
037import javax.swing.JOptionPane;
038import name.gano.astro.AstroConst;
039import name.gano.astro.GeoFunctions;
040import name.gano.astro.Kepler;
041import jsattrak.utilities.TLE;
042import name.gano.astro.coordinates.J2kCoordinateConversion;
043import name.gano.astro.propogators.sgp4_cssi.SGP4SatData;
044import name.gano.astro.propogators.sgp4_cssi.SGP4unit;
045import name.gano.astro.propogators.sgp4_cssi.SGP4utils;
046import name.gano.worldwind.modelloader.WWModel3D_new;
047import net.java.joglutils.model.ModelFactory;
048*/
049/**
050 * 
051 *
052 * @author ganos
053 */
054public class SatelliteTleSGP4 extends AbstractSatellite
055{
056    private TLE tle;
057    private SGP4SatData sgp4SatData; // sgp4 propogator data
058    
059    // current time - julian date
060    double currentJulianDate = -1;
061    
062    // TLE epoch -- used to calculate how old is TLE - Julian Date
063    double tleEpochJD = -1; // no age
064    
065    // J2000 position and velocity vectors
066    private double[] j2kPos = new double[3]; // meters
067    private double[] j2kVel = new double[3]; // meters/sec
068    // true-equator, mean equinox TEME of date
069    private double[] posTEME = new double[3];  // true-equator, mean equinox TEME of date position for LLA calcs, meters
070    private double[] velTEME = new double[3]; // meters/sec
071    
072    // lat,long,alt  [radians, radians, m ]
073    private double[] lla = new double[3];
074    
075    // plot options 
076    private boolean plot2d = true;
077//    private Color satColor = Color.RED; // randomize in future
078    private boolean plot2DFootPrint = true;
079    private boolean fillFootPrint = true;
080    private int numPtsFootPrint = 41; // number of points in footprint, used to be 101
081    
082    // ground track options  -- grounds tracks draw to asending nodes, re-calculated at acending nodes
083    boolean showGroundTrack = true;
084    private int grnTrkPointsPerPeriod = 81; // equally space in time >=2 // used to be 121
085    private double groundTrackLeadPeriodMultiplier = 2.0;  // how far forward to draw ground track - in terms of periods
086    private double groundTrackLagPeriodMultiplier = 1.0;  // how far behind to draw ground track - in terms of periods
087    double[][] latLongLead; // leading lat/long coordinates for ground track
088    double[][] latLongLag; // laging lat/long coordinates for ground track
089    private double[][] temePosLead; // leading TEME position coordinates for ground track
090    private double[][] temePosLag; // laging TEME position coordinates for ground track
091    private double[]   timeLead; // array for holding times associated with lead coordinates (Jul Date)
092    private double[]   timeLag; // array - times associated with lag coordinates (Jul Date)
093    boolean groundTrackIni = false; // if ground track has been initialized    
094    
095    private boolean showName2D = true; // show name in 2D plots
096    
097    // 3D Options
098    private boolean show3DOrbitTrace = true;
099    private boolean show3DFootprint = true;
100    private boolean show3DName = true; // not implemented to change yet
101    private boolean show3D = true; // no implemented to change yet, or to modify showing of sat
102    private boolean showGroundTrack3d = false;
103    private boolean show3DOrbitTraceECI = true; // show orbit in ECI mode otherwise , ECEF
104    
105        // 3D model parameters
106    private boolean use3dModel = false; // use custom 3D model (or default sphere)
107    private String threeDModelPath = "globalstar/Globalstar.3ds"; // path to the custom model, default= globalstar/Globalstar.3ds ?
108//    private transient WWModel3D_new threeDModel; // DO NOT STORE when saving -- need to reload this -- TOO MUCH DATA!
109    private double threeDModelSizeFactor = 300000;
110    
111    /** Creates a new instance of SatelliteProps - default properties with given name and TLE lines
112     * @param name name of satellite
113     * @param tleLine1 first line of two line element
114     * @param tleLine2 second line of two line element
115     * @throws Exception if TLE data is bad
116     */
117    public SatelliteTleSGP4(String name, String tleLine1, String tleLine2) throws Exception
118    {
119        // create internal TLE object
120        tle = new TLE(name,tleLine1,tleLine2);
121        
122        // initialize sgp4 propogator data for the satellite
123        sgp4SatData = new SGP4SatData();
124        
125        // try to load TLE into propogator
126
127        // options - hard coded
128        char opsmode = SGP4utils.OPSMODE_IMPROVED; // OPSMODE_IMPROVED
129        SGP4unit.Gravconsttype gravconsttype = SGP4unit.Gravconsttype.wgs72;
130
131        // load TLE data as strings and INI all SGP4 data
132        boolean loadSuccess = SGP4utils.readTLEandIniSGP4(name, tleLine1, tleLine2, opsmode, gravconsttype, sgp4SatData);
133
134        // if there is an error loading send an exception
135        if (!loadSuccess)
136        {
137            throw new Exception("Error loading TLE error code:" + sgp4SatData.error);
138        }
139
140        // calculate TLE age
141        tleEpochJD = sgp4SatData.jdsatepoch;
142          
143    }
144/*    
145    @Override
146    public void updateTleData(TLE newTLE)
147    {
148        this.tle = newTLE; // save new TLE
149        
150        // new spg4 object
151        sgp4SatData = new SGP4SatData();
152        
153        // read TLE
154        // options - hard coded
155        char opsmode = SGP4utils.OPSMODE_IMPROVED; // OPSMODE_IMPROVED
156        SGP4unit.Gravconsttype gravconsttype = SGP4unit.Gravconsttype.wgs72;
157
158        // load TLE data as strings and INI all SGP4 data
159        boolean loadSuccess = SGP4utils.readTLEandIniSGP4(tle.getSatName(), tle.getLine1(), tle.getLine2(), opsmode, gravconsttype, sgp4SatData);
160
161        // if there is an error loading send an exception
162        if (!loadSuccess)
163        {
164            JOptionPane.showMessageDialog(null,"Error reading updated TLE, error code:" + sgp4SatData.error + "\n Satellite: "+ tle.getSatName());
165        }
166
167        // calculate TLE age
168        tleEpochJD = sgp4SatData.jdsatepoch;
169               
170        // ground track needs to be redone with new data
171        groundTrackIni = false;
172        
173        //System.out.println("Updated " + tle.getSatName() );
174    }
175*/    
176    public void propogate2JulDate(double julDate)
177    {
178        // save date
179        this.currentJulianDate = julDate;
180
181        // using JulDate because function uses time diff between jultDate of ephemeris, SGP4 uses UTC
182        // propogate satellite to given date - saves result in TEME to posTEME and velTEME in km, km/s
183        boolean propSuccess = SGP4unit.sgp4Prop2JD(sgp4SatData, julDate, posTEME, velTEME);
184        if(!propSuccess)
185        {
186            System.out.println("Error SGP4 Propagation failed for sat: " + sgp4SatData.name + ", JD: " + sgp4SatData.jdsatepoch + ", error code: "+ sgp4SatData.error);
187        }
188
189        // scale output to meters
190        for(int i=0;i<3;i++)
191        {
192            // TEME
193             posTEME[i] = posTEME[i]*1000.0;
194             velTEME[i] = velTEME[i]*1000.0;
195        }
196        
197        //print differene TT-UT
198        //System.out.println("TT-UT [days]= " + SDP4TimeUtilities.DeltaT(julDate-2450000)*24.0*60*60);
199        
200        
201        // SEG - 11 June 2009 -- new information (to me) on SGP4 propogator coordinate system:
202        // SGP4 output is in true equator and mean equinox (TEME) of Date *** note some think of epoch, but STK beleives it is of date from tests **
203        // It depends also on the source for the TLs if from the Nasa MCC might be MEME but most US Gov - TEME
204        // Also the Lat/Lon/Alt calculations are based on TEME (of Date) so that is correct as it was used before!
205        // References:
206        // http://www.stk.com/pdf/STKandSGP4/STKandSGP4.pdf  (STK's stance on SGP4)
207        // http://www.agi.com/resources/faqSystem/files/2144.pdf  (newer version of above)
208        // http://www.satobs.org/seesat/Aug-2004/0111.html
209        // http://celestrak.com/columns/v02n01/ "Orbital Coordinate Systems, Part I" by Dr. T.S. Kelso
210        // http://en.wikipedia.org/wiki/Earth_Centered_Inertial
211        // http://ccar.colorado.edu/asen5050/projects/projects_2004/aphanuphong/p1.html  (bad coefficients? conversion between TEME and J2000 (though slightly off?))
212        //  http://www.centerforspace.com/downloads/files/pubs/AIAA-2000-4025.pdf
213        // http://celestrak.com/software/vallado-sw.asp  (good software)
214
215        double mjd = julDate-AstroConst.JDminusMJD;
216
217        // get position information back out - convert to J2000 (does TT time need to be used? - no)
218        //j2kPos = CoordinateConversion.EquatorialEquinoxToJ2K(mjd, sdp4Prop.itsR); //julDate-2400000.5
219        //j2kVel = CoordinateConversion.EquatorialEquinoxToJ2K(mjd, sdp4Prop.itsV);
220        // based on new info about coordinate system, to get the J2K other conversions are needed!
221        // precession from rk5 -> mod
222        double ttt = (mjd-AstroConst.MJD_J2000) /36525.0;
223        double[][] A = J2kCoordinateConversion.teme_j2k(J2kCoordinateConversion.Direction.to,ttt, 24, 2, 'a');
224        // rotate position and velocity
225        j2kPos = J2kCoordinateConversion.matvecmult( A, posTEME);
226        j2kVel = J2kCoordinateConversion.matvecmult( A, velTEME);
227
228        //System.out.println("Date: " + julDate +", Pos: " + sdp4Prop.itsR[0] + ", " + sdp4Prop.itsR[1] + ", " + sdp4Prop.itsR[2]);
229
230        // save old lat/long for ascending node check
231        double[] oldLLA = lla.clone(); // copy old LLA
232        
233        // calculate Lat,Long,Alt - must use Mean of Date (MOD) Position
234        lla = GeoFunctions.GeodeticLLA(posTEME,julDate-AstroConst.JDminusMJD); // j2kPos
235        
236        // Check to see if the ascending node has been passed
237        if(showGroundTrack==true)
238        {
239            if(groundTrackIni == false ) // update ground track needed
240            {
241                initializeGroundTrack();
242            }
243            else if( oldLLA[0] < 0 && lla[0] >=0) // check for ascending node pass
244            {
245                //System.out.println("Ascending NODE passed: " + tle.getSatName() );
246                initializeGroundTrack(); // for new ini each time
247                
248            } // ascending node passed
249            
250        } // if show ground track is true
251        
252        // if 3D model - update its properties -- NOT DONE HERE - done in OrbitModelRenderable (so it can be done for any sat)
253               
254    } // propogate2JulDate
255    
256    
257    
258    // initalize the ground track from any starting point, as long as Juldate !=-1
259    private void initializeGroundTrack()
260    {
261        if(currentJulianDate == -1)
262        {
263            // nothing to do yet, we haven't been given an initial time
264            return;
265        }
266        
267        // find time of last acending node crossing
268        
269        // initial guess -- the current time        
270        double lastAscendingNodeTime = currentJulianDate; // time of last ascending Node Time
271        
272        // calculate period - in minutes
273        double periodMin = Kepler.CalculatePeriod(AstroConst.GM_Earth,j2kPos,j2kVel)/(60.0);
274        //System.out.println("period [min] = "+periodMin);
275        
276        // time step divisions (in fractions of a day)
277        double fracOfPeriod = 15.0;
278        double timeStep = (periodMin/(60.0*24.0)) / fracOfPeriod;
279        
280        // first next guess
281        double newGuess1 = lastAscendingNodeTime - timeStep;
282        
283        // latitude variables
284        double lat0 =  lla[0]; //  current latitude
285        double lat1 = (calculateLatLongAltXyz(newGuess1))[0]; // calculate latitude values       
286        
287        // bracket the crossing using timeStep step sizes
288        while( !( lat0>=0 && lat1<0 ) )
289        {
290            // move back a step
291            lastAscendingNodeTime = newGuess1;
292            lat0 = lat1;
293            
294            // next guess
295            newGuess1 = lastAscendingNodeTime - timeStep;
296            
297            // calculate latitudes of the new value
298            lat1 = (calculateLatLongAltXyz(newGuess1))[0];
299        } // while searching for ascending node
300        
301              
302        // secand method -- determine within a second!
303        double outJul = secantMethod(lastAscendingNodeTime-timeStep, lastAscendingNodeTime, 1.0/(60.0*60.0*24.0), 20);
304        //System.out.println("Guess 1:" + (lastAscendingNodeTime-timeStep) );
305        //System.out.println("Guess 2:" + (lastAscendingNodeTime));
306        //System.out.println("Answer: " + outJul);
307        
308        // update times: Trust Period Calculations for how far in the future and past to calculate out to
309        // WARNING: period calculation is based on osculating elements may not be 100% accurate
310        //          as this is just for graphical updates should be okay (no mid-course corrections assumed)
311        lastAscendingNodeTime = outJul;
312        double leadEndTime = lastAscendingNodeTime + groundTrackLeadPeriodMultiplier*periodMin/(60.0*24); // Julian Date for last lead point (furthest in future)
313        double lagEndTime = lastAscendingNodeTime - groundTrackLagPeriodMultiplier*periodMin/(60.0*24); // Julian Date for the last lag point (furthest in past)
314        
315        // fill in lead/lag arrays
316        fillGroundTrack(lastAscendingNodeTime,leadEndTime,lagEndTime);
317        
318        groundTrackIni = true;
319        return;
320        
321    } // initializeGroundTrack
322    
323    // fill in the Ground Track given Jul Dates for 
324    // 
325    private void fillGroundTrack(double lastAscendingNodeTime, double leadEndTime, double lagEndTime)
326    {
327        // points in the lead direction
328        int ptsLead = (int)Math.ceil(grnTrkPointsPerPeriod*groundTrackLeadPeriodMultiplier);
329        latLongLead = new double[ptsLead][3];        
330        temePosLead =  new double[ptsLead][3];
331        timeLead = new double[ptsLead];
332                
333        for(int i=0;i<ptsLead;i++)
334        {
335            double ptTime = lastAscendingNodeTime + i*(leadEndTime-lastAscendingNodeTime)/(ptsLead-1);
336            
337           // PUT HERE calculate lat lon
338            double[] ptLlaXyz = calculateLatLongAltXyz(ptTime);
339            
340            latLongLead[i][0] = ptLlaXyz[0]; // save lat
341            latLongLead[i][1] = ptLlaXyz[1]; // save long
342            latLongLead[i][2] = ptLlaXyz[2]; // save altitude
343            
344            temePosLead[i][0] = ptLlaXyz[3]; // x
345            temePosLead[i][1] = ptLlaXyz[4]; // y
346            temePosLead[i][2] = ptLlaXyz[5]; // z
347            
348            timeLead[i] = ptTime; // save time
349            
350        } // for each lead point
351        
352        // points in the lag direction
353        int ptsLag = (int)Math.ceil(grnTrkPointsPerPeriod*groundTrackLagPeriodMultiplier);
354        latLongLag = new double[ptsLag][3];
355        temePosLag = new double[ptsLag][3];
356        timeLag = new double[ptsLag];
357        
358        for(int i=0;i<ptsLag;i++)
359        {
360            double ptTime = lastAscendingNodeTime + i*(lagEndTime-lastAscendingNodeTime)/(ptsLag-1);
361            
362            double[] ptLlaXyz = calculateLatLongAltXyz(ptTime);
363             
364            latLongLag[i][0] = ptLlaXyz[0]; // save lat
365            latLongLag[i][1] = ptLlaXyz[1]; // save long
366            latLongLag[i][2] = ptLlaXyz[2]; // save alt
367            
368            temePosLag[i][0] = ptLlaXyz[3]; // x
369            temePosLag[i][1] = ptLlaXyz[4]; // y
370            temePosLag[i][2] = ptLlaXyz[5]; // z
371            
372            timeLag[i] = ptTime;
373            
374        } // for each lag point
375    } // fillGroundTrack
376   
377    // takes in JulDate, returns lla and teme position
378    private double[] calculateLatLongAltXyz(double ptTime)
379    {
380        double[] ptPos = calculateTemePositionFromUT(ptTime);
381        
382        // get lat and long
383        double[] ptLla = GeoFunctions.GeodeticLLA(ptPos,ptTime-AstroConst.JDminusMJD);
384        
385        double[] ptLlaXyz = new double[] {ptLla[0],ptLla[1],ptLla[2],ptPos[0],ptPos[1],ptPos[2]};
386        
387        return ptLlaXyz;
388    } // calculateLatLongAlt
389    
390    // 
391   
392    /**
393     * Calculate J2K position of this sat at a given JulDateTime (doesn't save the time) - can be useful for event searches or optimization
394     * @param julDate - julian date
395     * @return j2k position of satellite in meters
396     */
397/*
398    @Override
399    public double[] calculateJ2KPositionFromUT(double julDate)
400    {
401        double[] ptPos = calculateTemePositionFromUT(julDate);
402
403        double mjd = julDate-AstroConst.JDminusMJD;
404
405        // get position information back out - convert to J2000
406        // precession from rk5 -> mod
407        double ttt = (mjd-AstroConst.MJD_J2000) /36525.0;
408        double[][] A = J2kCoordinateConversion.teme_j2k(J2kCoordinateConversion.Direction.to,ttt, 24, 2, 'a');
409        // rotate position
410        double[] j2kPosI = J2kCoordinateConversion.matvecmult( A, ptPos);
411        
412        return j2kPosI;
413        
414    } // calculatePositionFromUT
415*/    
416    /**
417     * Calculate true-equator, mean equinox (TEME) of date position of this sat at a given JulDateTime (doesn't save the time) - can be useful for event searches or optimization
418     * @param julDate - julian date
419     * @return j2k position of satellite in meters
420     */
421
422    public double[] calculateTemePositionFromUT(double julDate)
423    {
424        double[] ptPos = new double[3];
425        double[] ptVel = new double[3];
426
427        // using JulDate because function uses time diff between jultDate of ephemeris, SGP4 uses UTC
428        // propogate satellite to given date - saves result in TEME to posTEME and velTEME in km, km/s
429        boolean propSuccess = SGP4unit.sgp4Prop2JD(sgp4SatData, julDate, ptPos, ptVel);
430        if(!propSuccess)
431        {
432            System.out.println("Error (2) SGP4 Propagation failed for sat: " + sgp4SatData.name + ", JD: " + sgp4SatData.jdsatepoch + ", error code: "+ sgp4SatData.error);
433        }
434
435        // scale output to meters
436        for(int i=0;i<3;i++)
437        {
438            // TEME
439             ptPos[i] = ptPos[i]*1000.0;
440        }
441        
442        return ptPos;
443        
444    } // calculatePositionFromUT
445    
446    
447    //---------------------------------------
448    //  SECANT Routines to find Crossings of the Equator (hopefully Ascending Nodes)
449    // xn_1 = date guess 1
450    // xn date guess 2
451    // tol = convergence tolerance
452    // maxIter = maximum iterations allowed
453    // RETURNS: double = julian date of crossing
454    private double secantMethod(double xn_1, double xn, double tol, int maxIter)
455    {
456
457        double d;
458        
459        // calculate functional values at guesses
460        double fn_1 = latitudeGivenJulianDate(xn_1);
461        double fn = latitudeGivenJulianDate(xn);
462        
463        for (int n = 1; n <= maxIter; n++)
464        {
465            d = (xn - xn_1) / (fn - fn_1) * fn;
466            if (Math.abs(d) < tol) // convergence check
467            {
468                //System.out.println("Iters:"+n);
469                return xn;
470            }
471            
472            // save past point
473            xn_1 = xn;
474            fn_1 = fn;
475            
476            // new point
477            xn = xn - d;
478            fn = latitudeGivenJulianDate(xn);
479        }
480        
481        System.out.println("Warning: Secant Method - Max Iteration limit reached finding Asending Node.");
482        
483        return xn;
484    } // secantMethod
485    
486    private double latitudeGivenJulianDate(double julDate)
487    {
488        // computer latiude of the spacecraft at a given date
489        double[] ptPos = calculateTemePositionFromUT(julDate);
490        
491        // get lat and long
492        double[] ptLla = GeoFunctions.GeodeticLLA(ptPos,julDate-AstroConst.JDminusMJD);
493        
494        return ptLla[0]; // pass back latitude
495        
496    } // latitudeGivenJulianDate
497
498    //--------------------------------------
499    
500    public void setShowGroundTrack(boolean showGrndTrk)
501    {
502        showGroundTrack = showGrndTrk;
503        
504        if(showGrndTrk == false)
505        {
506            groundTrackIni = false; 
507            latLongLead = new double[][] {{}}; // save some space
508            latLongLag = new double[][] {{}}; // sace some space
509            temePosLag = new double[][] {{}};
510            temePosLead = new double[][] {{}};
511            timeLead = new double[] {};
512            timeLag = new double[] {};
513        }
514        else
515        {
516            // ground track needs to be initalized
517            initializeGroundTrack();
518        }
519    }
520/*    
521    public boolean getShowGroundTrack()
522    {
523        return showGroundTrack;
524    }
525*/ 
526    public double getLatitude()
527    {
528        return lla[0];
529    }
530    
531    public double getLongitude()
532    {
533        return lla[1];
534    }
535    
536    public double getAltitude()
537    {
538        return lla[2];
539    }
540   
541    public double[] getLLA()
542    {
543        return lla;
544    }
545/*    
546    // TT or UTC? = UTC
547    public double getSatTleEpochJulDate()
548    {
549        return sgp4SatData.jdsatepoch;
550    }
551    
552    public double getCurrentJulDate()
553    {
554        return currentJulianDate;
555    }
556    
557    public double[] getJ2000Position()
558    {
559        return j2kPos.clone();
560    }
561    
562    public double[] getJ2000Velocity()
563    {
564        return j2kVel.clone();
565    }
566    
567    public boolean getPlot2D()
568    {
569        return plot2d;
570    }
571    
572    public Color getSatColor()
573    { 
574        return satColor;
575    }
576    
577    public boolean getPlot2DFootPrint()
578    {
579        return plot2DFootPrint;
580    }
581    
582    public boolean getGroundTrackIni()
583    {
584        return groundTrackIni;
585    }
586    
587    public void setGroundTrackIni2False()
588    {
589        // forces repaint of ground track next update
590        groundTrackIni = false;
591    }
592    
593    public int getNumGroundTrackLeadPts()
594    {
595        return latLongLead.length;
596    }
597        
598    public int getNumGroundTrackLagPts()
599    {
600        return latLongLag.length;
601    }
602        
603    public double[] getGroundTrackLlaLeadPt(int index)
604    {
605        return new double[] {latLongLead[index][0],latLongLead[index][1],latLongLead[index][2]};
606    }
607    
608    public double[] getGroundTrackLlaLagPt(int index)
609    {
610        return new double[] {latLongLag[index][0],latLongLag[index][1],latLongLag[index][2]};
611    }
612    
613    public double[] getGroundTrackXyzLeadPt(int index)
614    {
615        return new double[] {getTemePosLead()[index][0],getTemePosLead()[index][1],getTemePosLead()[index][2]};
616    }
617    
618    public double[] getGroundTrackXyzLagPt(int index)
619    {
620        return new double[] {getTemePosLag()[index][0],getTemePosLag()[index][1],getTemePosLag()[index][2]};
621    }
622    
623    
624    // returns satellite's current perdiod based on current pos/vel in Minutes
625    public double getPeriod()
626    {
627        return Kepler.CalculatePeriod(AstroConst.GM_Earth,j2kPos,j2kVel)/(60.0);
628    }
629    
630    public String getName()
631    {
632        return tle.getSatName();
633    }
634    
635    public double[] getKeplarianElements()
636    {
637        return Kepler.SingularOsculatingElements( AstroConst.GM_Earth, j2kPos, j2kVel ); 
638    }
639    
640    public double getTleEpochJD()
641    {
642        return tleEpochJD;
643    }
644    
645    public double getTleAgeDays()
646    {
647        return currentJulianDate - tleEpochJD;
648    }
649
650    public int getNumPtsFootPrint()
651    {
652        return numPtsFootPrint;
653    }
654
655    public void setNumPtsFootPrint(int numPtsFootPrint)
656    {
657        this.numPtsFootPrint = numPtsFootPrint;
658    }
659
660    public boolean isShowName2D()
661    {
662        return showName2D;
663    }
664
665    public void setShowName2D(boolean showName2D)
666    {
667        this.showName2D = showName2D;
668    }
669
670    public boolean isFillFootPrint()
671    {
672        return fillFootPrint;
673    }
674
675    public void setFillFootPrint(boolean fillFootPrint)
676    {
677        this.fillFootPrint = fillFootPrint;
678    }
679
680    public int getGrnTrkPointsPerPeriod()
681    {
682        return grnTrkPointsPerPeriod;
683    }
684
685    public void setGrnTrkPointsPerPeriod(int grnTrkPointsPerPeriod)
686    {
687        this.grnTrkPointsPerPeriod = grnTrkPointsPerPeriod;
688    }
689
690    public double getGroundTrackLeadPeriodMultiplier()
691    {
692        return groundTrackLeadPeriodMultiplier;
693    }
694
695    public void setGroundTrackLeadPeriodMultiplier(double groundTrackLeadPeriodMultiplier)
696    {
697        this.groundTrackLeadPeriodMultiplier = groundTrackLeadPeriodMultiplier;
698    }
699
700    public double getGroundTrackLagPeriodMultiplier()
701    {
702        return groundTrackLagPeriodMultiplier;
703    }
704
705    public void setGroundTrackLagPeriodMultiplier(double groundTrackLagPeriodMultiplier)
706    {
707        this.groundTrackLagPeriodMultiplier = groundTrackLagPeriodMultiplier;
708    }
709
710    public void setPlot2d(boolean plot2d)
711    {
712        this.plot2d = plot2d;
713    }
714
715    public void setSatColor(Color satColor)
716    {
717        this.satColor = satColor;
718    }
719
720    public void setPlot2DFootPrint(boolean plot2DFootPrint)
721    {
722        this.plot2DFootPrint = plot2DFootPrint;
723    }
724*/
725    public double[] getTEMEPos()
726    {
727        return posTEME.clone();
728    }
729/*
730    public boolean isShow3DOrbitTrace()
731    {
732        return show3DOrbitTrace;
733    }
734
735    public void setShow3DOrbitTrace(boolean show3DOrbitTrace)
736    {
737        this.show3DOrbitTrace = show3DOrbitTrace;
738    }
739
740    public boolean isShow3DFootprint()
741    {
742        return show3DFootprint;
743    }
744
745    public void setShow3DFootprint(boolean show3DFootprint)
746    {
747        this.show3DFootprint = show3DFootprint;
748    }
749
750    public boolean isShow3DName()
751    {
752        return show3DName;
753    }
754
755    public void setShow3DName(boolean show3DName)
756    {
757        this.show3DName = show3DName;
758    }
759
760    public boolean isShowGroundTrack3d()
761    {
762        return showGroundTrack3d;
763    }
764
765    public void setShowGroundTrack3d(boolean showGroundTrack3d)
766    {
767        this.showGroundTrack3d = showGroundTrack3d;
768    }
769
770    public boolean isShow3DOrbitTraceECI()
771    {
772        return show3DOrbitTraceECI;
773    }
774
775    public void setShow3DOrbitTraceECI(boolean show3DOrbitTraceECI)
776    {
777        this.show3DOrbitTraceECI = show3DOrbitTraceECI;
778    }
779
780    public boolean isShow3D()
781    {
782        return show3D;
783    }
784
785    public void setShow3D(boolean show3D)
786    {
787        this.show3D = show3D;
788    }
789
790    public // laging lat/long coordinates for ground track
791    double[][] getTemePosLead()
792    {
793        return temePosLead;
794    }
795
796    public // leading Mean of date position coordinates for ground track
797    double[][] getTemePosLag()
798    {
799        return temePosLag;
800    }
801
802    public // laging Mean of date position coordinates for ground track
803    double[] getTimeLead()
804    {
805        return timeLead;
806    }
807
808    public // array for holding times associated with lead coordinates (Jul Date)
809    double[] getTimeLag()
810    {
811        return timeLag;
812    }
813    
814    // 3D model -------------------------
815    public boolean isUse3dModel()
816    {
817        return use3dModel; 
818    }
819    
820    public void setUse3dModel(boolean use3dModel)
821    {
822        this.use3dModel = use3dModel;
823        
824        if(use3dModel && threeDModelPath.length() > 0)
825        {
826            // check that file exsists? - auto done in loader
827            
828            //String path = "data/models/globalstar/Globalstar.3ds";
829            //String path = "data/models/isscomplete/iss_complete.3ds";
830            
831            loadNewModel(threeDModelPath);
832        }
833    }
834    
835    public String getThreeDModelPath()
836    {
837        return threeDModelPath;
838    }
839*/    
840    /**
841     * Relative path to the model -- relative from "user.dir"/data/models/
842     * @param path
843     */
844/*
845    public void setThreeDModelPath(String path)
846    {
847        if(use3dModel && !(path.equalsIgnoreCase(this.threeDModelPath)) )
848        {
849            // need to load the model
850            loadNewModel(path);//"test/data/globalstar/Globalstar.3ds");
851        }
852        
853        this.threeDModelPath = path; // save path no matter
854    }
855    
856    private void loadNewModel(String path)
857    {
858        String localPath = "data/models/"; // path to models root from user.dir
859        
860        try
861            {
862                net.java.joglutils.model.geometry.Model model3DS = ModelFactory.createModel(localPath + path);
863                //model3DS.setUseLighting(false); // turn off lighting!
864
865                threeDModel =  new WWModel3D_new(model3DS,
866                        new Position(Angle.fromRadians(this.getLatitude()),
867                        Angle.fromRadians(this.getLongitude()),
868                        this.getAltitude()));
869
870                threeDModel.setMaitainConstantSize(true);
871                threeDModel.setSize(threeDModelSizeFactor); // this needs to be a property!
872                
873                threeDModel.updateAttitude(this); // fixes attitude intitially
874                
875            }catch(Exception e)
876            {
877                System.out.println("ERROR LOADING 3D MODEL");
878            }
879    }
880    
881    public WWModel3D_new getThreeDModel()
882    {
883        return threeDModel;
884    }    
885    
886    public  double[] getTEMEVelocity()
887    {
888        return velTEME.clone();
889    }
890
891    public double getThreeDModelSizeFactor()
892    {
893        return threeDModelSizeFactor;
894    }
895
896    public void setThreeDModelSizeFactor(double modelSizeFactor)
897    {
898        // should the 3D model be reloaded now?
899        if(modelSizeFactor != threeDModelSizeFactor && use3dModel && threeDModelPath.length()>0)
900        {
901            //loadNewModel(threeDModelPath);
902            if(threeDModel != null)
903            {
904                threeDModel.setSize(modelSizeFactor);
905            }
906        }
907        
908        this.threeDModelSizeFactor = modelSizeFactor;
909    }
910    
911    @Override
912    public String toString()
913    {
914        return this.tle.getSatName();
915    }
916*/    
917} // SatelliteProps