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 }