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