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 008 import edu.nrao.sss.geom.EarthPosition; 009 import edu.nrao.sss.measure.Angle; 010 import edu.nrao.sss.measure.ArcUnits; 011 import edu.nrao.sss.measure.Latitude; 012 import edu.nrao.sss.measure.LocalSiderealTime; 013 import edu.nrao.sss.measure.Longitude; 014 015 /** 016 * A converter that converts only equatorial positions to or from 017 * horizontal positions. 018 * <p> 019 * <b>Version Info:</b> 020 * <table style="margin-left:2em"> 021 * <tr><td>$Revision: 1242 $</td></tr> 022 * <tr><td>$Date: 2008-04-28 08:46:17 -0600 (Mon, 28 Apr 2008) $</td></tr> 023 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 024 * </table></p> 025 * 026 * @author David M. Harland 027 * @since 2008-02-27 028 */ 029 public class EquatorialHorizontalConverter 030 implements CelestialCoordinateConverter 031 { 032 public SkyPosition createFrom(SkyPosition position, 033 CelestialCoordinateSystem toSystem, 034 Epoch toEpoch, 035 EarthPosition observer, 036 LocalSiderealTime lst) 037 throws CoordinateConversionException 038 { 039 //TODO Do we implicitly support only J2000? 040 // If so, throw exception for B1950? 041 042 CelestialCoordinateSystem fromSystem = position.getCoordinateSystem(); 043 044 SkyPosition sp = null; 045 046 //TODO do null-conversion as a courtesy? 047 // Note: non-trivial if HORZ to HORZ and position has 048 // changed. 049 050 if (fromSystem.equals(EQUATORIAL) && toSystem.equals(HORIZONTAL)) 051 { 052 sp = equatorialToHorizontal(position, observer, lst); 053 } 054 else if (fromSystem.equals(HORIZONTAL) && toSystem.equals(EQUATORIAL)) 055 { 056 sp = horizontalToEquatorial(position, observer, lst); 057 } 058 else 059 { 060 //TODO throw excep 061 } 062 063 return sp; 064 } 065 066 /** Creates an equatorial position from a horizontal. */ 067 private SkyPosition 068 horizontalToEquatorial(SkyPosition horizPosition, 069 EarthPosition observerPosition, 070 LocalSiderealTime lst) 071 { 072 Date time = lst.toDate(); 073 074 Angle elAngle = horizPosition.getLatitude(time).toAngle(); 075 Angle azAngle = horizPosition.getLongitude(time).toAngle(); 076 Angle latAngle = observerPosition.getLatitude().toAngle(); 077 078 //This algorithm is one that avoids arcsin and arccosine. 079 //It comes from http://stsdas.stsci.edu/cgi-bin/gethelp.cgi?dh2e.src 080 //(SLALIB) and works by transforming rectangular to polar coordinates. 081 082 BigDecimal SA = new BigDecimal(azAngle.sine()); 083 BigDecimal CA = new BigDecimal(azAngle.cosine()); 084 BigDecimal SE = new BigDecimal(elAngle.sine()); 085 BigDecimal CE = new BigDecimal(elAngle.cosine()); 086 BigDecimal SP = new BigDecimal(latAngle.sine()); 087 BigDecimal CP = new BigDecimal(latAngle.cosine()); 088 089 BigDecimal X = CA.negate().multiply(CE).multiply(SP); 090 BigDecimal temp = SE.multiply(CP); 091 X = X.add(temp); 092 093 BigDecimal Y = SA.negate().multiply(CE); 094 095 BigDecimal Z = CA.multiply(CE).multiply(CP); 096 temp = SE.multiply(SP); 097 Z = Z.add(temp); 098 099 BigDecimal Rsq = X.multiply(X); 100 temp = Y.multiply(Y); 101 Rsq = Rsq.add(temp); 102 103 double R = Math.sqrt(Rsq.doubleValue()); 104 105 double HA = (R == 0.0) ? 0.0: Math.atan2(Y.doubleValue(), X.doubleValue()); 106 107 Angle hourAngle = new Angle(BigDecimal.valueOf(HA), ArcUnits.RADIAN); 108 109 Angle declination = new Angle(BigDecimal.valueOf(Math.atan2(Z.doubleValue(), R)), 110 ArcUnits.RADIAN); 111 112 Longitude rightAscension = lst.getRightAscension(new Longitude(hourAngle)); 113 114 //Construct the new position 115 SimpleSkyPosition eqPos = 116 new SimpleSkyPosition(CelestialCoordinateSystem.EQUATORIAL, 117 Epoch.J2000); 118 eqPos.setLongitude(rightAscension); 119 eqPos.setLatitude(new Latitude(declination)); 120 121 return eqPos; 122 } 123 124 /** Creates a horizontal position from an equatorial. */ 125 private SkyPosition 126 equatorialToHorizontal(SkyPosition eqPosition, 127 EarthPosition observerPosition, 128 LocalSiderealTime lst) 129 { 130 Date time = lst.toDate(); 131 132 Angle decAngle = eqPosition.getLatitude(time).toAngle(); 133 Angle latAngle = observerPosition.getLatitude().toAngle(); 134 Angle hourAngle = lst.getHourAngle(eqPosition.getLongitude(time)).toAngle(); 135 136 //This algorithm is one that avoids arcsin and arccosine. 137 //It comes from http://stsdas.stsci.edu/cgi-bin/gethelp.cgi?de2h.src 138 //(SLALIB) and works by transforming rectangular to polar coordinates. 139 140 BigDecimal SH = new BigDecimal(hourAngle.sine()); 141 BigDecimal CH = new BigDecimal(hourAngle.cosine()); 142 BigDecimal SD = new BigDecimal(decAngle.sine()); 143 BigDecimal CD = new BigDecimal(decAngle.cosine()); 144 BigDecimal SP = new BigDecimal(latAngle.sine()); 145 BigDecimal CP = new BigDecimal(latAngle.cosine()); 146 147 BigDecimal X = CH.negate().multiply(CD).multiply(SP); 148 BigDecimal temp = SD.multiply(CP); 149 X = X.add(temp); 150 151 BigDecimal Y = SH.negate().multiply(CD); 152 153 BigDecimal Z = CH.multiply(CD).multiply(CP); 154 temp = SD.multiply(SP); 155 Z = Z.add(temp); 156 157 BigDecimal Rsq = X.multiply(X); 158 temp = Y.multiply(Y); 159 Rsq = Rsq.add(temp); 160 161 double R = Math.sqrt(Rsq.doubleValue()); 162 163 double A = (R == 0.0) ? 0.0: Math.atan2(Y.doubleValue(), X.doubleValue()); 164 165 Angle azimuth = new Angle(BigDecimal.valueOf(A), ArcUnits.RADIAN); 166 167 Angle elevation = new Angle(BigDecimal.valueOf(Math.atan2(Z.doubleValue(), R)), 168 ArcUnits.RADIAN); 169 170 //Construct the new position 171 SimpleSkyPosition horizPos = 172 new SimpleSkyPosition(CelestialCoordinateSystem.HORIZONTAL, 173 eqPosition.getEpoch()); 174 horizPos.setLongitude(new Longitude(azimuth)); 175 horizPos.setLatitude(new Latitude(elevation)); 176 177 return horizPos; 178 } 179 180 //============================================================================ 181 // 182 //============================================================================ 183 /* 184 public static void main(String... args) 185 { 186 LocalSiderealTime lst = new LocalSiderealTime(); 187 System.out.println("LST = "+lst.toDate()+"\n"); 188 189 EarthPosition observer = new EarthPosition(lst.getLocation(), Latitude.parse("34d 04' 43.497\""), lst.getTimeZone()); 190 System.out.println("Longitude = "+observer.getLongitude().toStringDms()+ 191 ", Latitude = "+observer.getLatitude().toStringDms()+"\n"); 192 193 SimpleSkyPosition eqPos = new SimpleSkyPosition(CelestialCoordinateSystem.EQUATORIAL, Epoch.J2000); 194 System.out.print("Orig RA/Dec: " ); displayPosition(eqPos); 195 196 EquatorialHorizontalConverter converter = new EquatorialHorizontalConverter(); 197 SkyPosition horzPos = converter.equatorialToHorizontal(eqPos, observer, lst); 198 System.out.print("Conv Az/El: " ); displayPosition(horzPos); 199 200 SkyPosition eqPos2 = converter.horizontalToEquatorial(horzPos, observer, lst); 201 System.out.print("Converted back: " ); displayPosition(eqPos2); 202 203 //The elevation of the celestial pole should equal latitude 204 System.out.println(); 205 eqPos.setLatitude(new Latitude(90.0)); 206 eqPos.setLongitude(new Longitude(0.0)); 207 horzPos = converter.equatorialToHorizontal(eqPos, observer, lst); 208 displayPosition(horzPos); 209 210 eqPos2 = converter.horizontalToEquatorial(horzPos, observer, lst); 211 displayPosition(eqPos2); 212 213 System.out.println(); 214 eqPos.setLongitude(new Longitude(60.0)); 215 eqPos.setLatitude(new Latitude(50.0)); 216 System.out.print("Orig RA/Dec: " ); displayPosition(eqPos); 217 horzPos = converter.equatorialToHorizontal(eqPos, observer, lst); 218 System.out.print("Conv Az/El: " ); displayPosition(horzPos); 219 eqPos2 = converter.horizontalToEquatorial(horzPos, observer, lst); 220 System.out.print("Converted back: " ); displayPosition(eqPos2); 221 } 222 private static void displayPosition(SkyPosition pos) 223 { 224 System.out.print(pos.getCoordinateSystem()); 225 if (pos.getCoordinateSystem().equals(EQUATORIAL)) 226 System.out.print("-"+pos.getEpoch()); 227 System.out.print(", "); 228 System.out.print(pos.getLongitude().toUnits(ArcUnits.DEGREE)); //.toStringHms()); 229 System.out.print(", "); 230 System.out.print(pos.getLatitude().toUnits(ArcUnits.DEGREE)); //.toStringDms()); 231 System.out.println(); 232 } 233 */ 234 }