001    package edu.nrao.sss.astronomy;
002    
003    import java.math.BigDecimal;
004    import java.util.Date;
005    
006    import static edu.nrao.sss.astronomy.CelestialCoordinateSystem.*;
007    import static edu.nrao.sss.measure.ArcUnits.*;
008    
009    import uk.ac.starlink.pal.AngleDR;
010    import uk.ac.starlink.pal.Galactic;
011    import uk.ac.starlink.pal.Pal;
012    
013    import edu.nrao.sss.geom.EarthPosition;
014    import edu.nrao.sss.measure.Latitude;
015    import edu.nrao.sss.measure.LocalSiderealTime;
016    import edu.nrao.sss.measure.Longitude;
017    
018    /**
019     * A coordinate converter based on the Positional Astronomy Library
020     * of the defunct Starlink project.  This class enlists the help of their
021     * <a href="http://star-www.rl.ac.uk/starjava/javadocs/uk/ac/starlink/pal/Pal.html">
022     * Pal</a>, which is a partial implementation of their
023     * <a href="http://www.starlink.rl.ac.uk/star/docs/sun67.htx/sun67.html">
024     * SLALIB</a> software.
025     * <p>
026     * This converter handles only the J2000 Equatorial, Ecliptic, and
027     * 1958 Galactic coordinate systems.</p>
028     * <p>
029     * <b>Version Info:</b>
030     * <table style="margin-left:2em">
031     *   <tr><td>$Revision: 1707 $</td></tr>
032     *   <tr><td>$Date: 2008-11-14 10:23:59 -0700 (Fri, 14 Nov 2008) $</td></tr>
033     *   <tr><td>$Author: dharland $ (last person to modify)</td></tr>
034     * </table></p>
035     * 
036     * @author David M. Harland
037     * @since 2008-02-28
038     */
039    //In the little bit of testing done so far, the equatorial <--> galactic
040    //conversions match the HEASARC numbers extremely well.  The conversions
041    //to/from ecliptic, though, are off from 1/1000 to 1/10 degree.
042    //--DMH 2/28/2008
043    
044    public class StarlinkPalConverter
045      implements CelestialCoordinateConverter
046    {
047      private static final Pal STARLINK_PAL = new Pal();
048      
049      public SkyPosition createFrom(SkyPosition               position,
050                                    CelestialCoordinateSystem toSystem,
051                                    Epoch                     toEpoch,
052                                    EarthPosition             observer,
053                                    LocalSiderealTime         lst)
054        throws CoordinateConversionException
055      {
056        SkyPosition convertedPosition = null;
057        
058        //TODO validate the from/to ccs & epoch
059        //Epoch fromEpoch = position.getEpoch();
060        CelestialCoordinateSystem fromSystem = position.getCoordinateSystem();
061        
062        if (lst == null)
063          lst = new LocalSiderealTime();
064        
065        switch (fromSystem)
066        {
067          case EQUATORIAL:
068            convertedPosition = convertEquatorial(position, toSystem, lst);
069            break;
070          
071          case ECLIPTIC:
072            convertedPosition = convertEcliptic(position, toSystem, lst);
073            break;
074            
075          case GALACTIC:
076            convertedPosition = convertGalactic(position, toSystem, lst);
077            break;
078          
079          default:
080            //TODO programmer error: already handled by validation method
081        }
082        
083        return convertedPosition;
084      }
085      
086      //============================================================================
087      // A-to-* CONVERSIONS
088      //============================================================================
089      
090      private SkyPosition convertEquatorial(SkyPosition               sp,
091                                            CelestialCoordinateSystem ccs,
092                                            LocalSiderealTime         lst)
093      {
094        switch (ccs)
095        {
096          case EQUATORIAL:  return SimpleSkyPosition.copy(sp, lst.toDate());
097          case ECLIPTIC:    return equatorialToEcliptic(sp, lst);
098          case GALACTIC:    return equatorialToGalactic(sp, lst);
099          
100          default:
101            //TODO programmer error: already handled by validation method
102            return null;
103        }
104      }
105      
106      
107      private SkyPosition convertEcliptic(SkyPosition               sp,
108                                          CelestialCoordinateSystem ccs,
109                                          LocalSiderealTime         lst)
110      {
111        switch (ccs)
112        {
113          case EQUATORIAL:  return eclipticToEquatorial(sp, lst);
114          case ECLIPTIC:    return SimpleSkyPosition.copy(sp, lst.toDate());
115          case GALACTIC:    return eclipticToGalactic(sp, lst);
116          
117          default:
118            //TODO programmer error: already handled by validation method
119            return null;
120        }
121      }
122      
123      
124      private SkyPosition convertGalactic(SkyPosition               sp,
125                                          CelestialCoordinateSystem ccs,
126                                          LocalSiderealTime         lst)
127      {
128        switch (ccs)
129        {
130          case EQUATORIAL:  return galacticToEquatorial(sp, lst);
131          case ECLIPTIC:    return galacticToEcliptic(sp, lst);
132          case GALACTIC:    return SimpleSkyPosition.copy(sp, lst.toDate());
133          
134          default:
135            //TODO programmer error: already handled by validation method
136            return null;
137        }
138      }
139      
140      //============================================================================
141      // A-to-B CONVERSIONS
142      //============================================================================
143      
144      private SkyPosition equatorialToEcliptic(SkyPosition       origPos,
145                                               LocalSiderealTime lst)
146      {
147        AngleDR raDec = toAngleDR(origPos, lst);
148        AngleDR eclip =
149          STARLINK_PAL.Eqecl(raDec,
150                             lst.toJulianDate().modifiedValue().doubleValue());
151        
152        return toSkyPos(eclip, ECLIPTIC);
153      }
154      
155      
156      private SkyPosition eclipticToEquatorial(SkyPosition       origPos,
157                                               LocalSiderealTime lst)
158      {
159        AngleDR eclip = toAngleDR(origPos, lst);
160        AngleDR raDec =
161          STARLINK_PAL.Ecleq(eclip,
162                             lst.toJulianDate().modifiedValue().doubleValue());
163        
164        return toSkyPos(raDec, EQUATORIAL);
165      }
166      
167      
168      private SkyPosition equatorialToGalactic(SkyPosition       origPos,
169                                               LocalSiderealTime lst)
170      {
171        AngleDR  raDec    = toAngleDR(origPos, lst);
172        Galactic galactic = STARLINK_PAL.Eqgal(raDec);
173    
174        return toSkyPos(galactic);
175      }
176      
177      
178      private SkyPosition galacticToEquatorial(SkyPosition       origPos,
179                                               LocalSiderealTime lst)
180      {
181        Galactic galactic = toGalactic(origPos, lst);
182        AngleDR  raDec    = STARLINK_PAL.Galeq(galactic);
183    
184        return toSkyPos(raDec, EQUATORIAL);
185      }
186      
187      
188      private SkyPosition eclipticToGalactic(SkyPosition       origPos,
189                                             LocalSiderealTime lst)
190      {
191        AngleDR eclip = toAngleDR(origPos, lst);
192        AngleDR raDec =
193          STARLINK_PAL.Ecleq(eclip,
194                             lst.toJulianDate().modifiedValue().doubleValue());
195        
196        Galactic galactic = STARLINK_PAL.Eqgal(raDec);
197    
198        return toSkyPos(galactic);
199      }
200      
201      
202      private SkyPosition galacticToEcliptic(SkyPosition       origPos,
203                                             LocalSiderealTime lst)
204      {
205        Galactic galactic = toGalactic(origPos, lst);
206        AngleDR  raDec    = STARLINK_PAL.Galeq(galactic);
207    
208        AngleDR eclip =
209          STARLINK_PAL.Eqecl(raDec,
210                             lst.toJulianDate().modifiedValue().doubleValue());
211        
212        return toSkyPos(eclip, ECLIPTIC);
213      }
214      
215      //============================================================================
216      // STARLINK <---> SSS CONVERSIONS
217      //============================================================================
218      
219      private AngleDR toAngleDR(SkyPosition sp, LocalSiderealTime lst)
220      {
221        Date time = lst.toDate();
222        
223        return new AngleDR(sp.getLongitude(time).toUnits(RADIAN).doubleValue(),
224                           sp.getLatitude(time).toUnits(RADIAN).doubleValue());
225    
226      }
227      
228      
229      private Galactic toGalactic(SkyPosition sp, LocalSiderealTime lst)
230      {
231        Date time = lst.toDate();
232        
233        return new Galactic(sp.getLongitude(time).toUnits(RADIAN).doubleValue(),
234                            sp.getLatitude(time).toUnits(RADIAN).doubleValue());
235    
236      }
237    
238      
239      private SkyPosition toSkyPos(AngleDR angleDR, CelestialCoordinateSystem ccs)
240      {
241        SimpleSkyPosition sp = new SimpleSkyPosition(ccs, Epoch.J2000);
242        
243        sp.setLongitude(new Longitude(new BigDecimal(angleDR.getAlpha()), RADIAN));
244        sp.setLatitude(new Latitude(new BigDecimal(angleDR.getDelta()), RADIAN));
245        
246        return sp;
247      }
248    
249      
250      private SkyPosition toSkyPos(Galactic galactic)
251      {
252        SimpleSkyPosition sp = new SimpleSkyPosition(GALACTIC, Epoch.J2000);
253        
254        sp.setLongitude(new Longitude(new BigDecimal(galactic.getLongitude()), RADIAN));
255        sp.setLatitude(new Latitude(new BigDecimal(galactic.getLatitude()), RADIAN));
256        
257        return sp;
258      }
259      
260      //============================================================================
261      // 
262      //============================================================================
263      /*
264      public static void main(String... args) throws Exception
265      {
266        //RA/Dec J2000 positions
267        SimpleSkyPosition eq = new SimpleSkyPosition(EQUATORIAL, Epoch.J2000);
268        eq.setLongitude(new Longitude(266.404996)); //10.684625));
269        eq.setLatitude(new Latitude(-28.936172)); //41.269278));
270        
271        System.out.println("J2000:    " + eq.getLongitude().toUnits(DEGREE) +
272                           ", " +         eq.getLatitude().toUnits(DEGREE));
273        
274        StarlinkPalConverter converter = new StarlinkPalConverter();
275        LocalSiderealTime lst = new LocalSiderealTime();
276        
277        SkyPosition ecliptic = converter.createFrom(eq, ECLIPTIC, Epoch.J2000, null, lst);
278        System.out.println("\nEcliptic: " + ecliptic.getLongitude().toUnits(DEGREE) +
279                           ", " +           ecliptic.getLatitude().toUnits(DEGREE));
280        
281        SkyPosition galactic = converter.createFrom(eq, GALACTIC, Epoch.J2000, null, lst);
282        System.out.println("\nGalactic: " + galactic.getLongitude().toUnits(DEGREE) +
283                           ", " +           galactic.getLatitude().toUnits(DEGREE));
284      }
285      */
286      /*
287      public static void main(String... args) throws Exception
288      {
289        //Galactic positions
290        SimpleSkyPosition g = new SimpleSkyPosition(GALACTIC, Epoch.J2000);
291        g.setLongitude(new Longitude(0.0));
292        g.setLatitude(new Latitude(0.0));
293        
294        System.out.println("Galactic: " + g.getLongitude().toUnits(DEGREE) +
295                           ", " +         g.getLatitude().toUnits(DEGREE));
296        
297        StarlinkPalConverter converter = new StarlinkPalConverter();
298        LocalSiderealTime lst = new LocalSiderealTime();
299        
300        SkyPosition ecliptic = converter.createFrom(g, ECLIPTIC, Epoch.J2000, null, lst);
301        System.out.println("\nEcliptic: " + ecliptic.getLongitude().toUnits(DEGREE) +
302                           ", " +           ecliptic.getLatitude().toUnits(DEGREE));
303        
304        SkyPosition j2000 = converter.createFrom(g, EQUATORIAL, Epoch.J2000, null, lst);
305        System.out.println("\nJ2000:    " + j2000.getLongitude().toUnits(DEGREE) +
306                           ", " +           j2000.getLatitude().toUnits(DEGREE));
307      }
308      */
309    }