001 package edu.nrao.sss.model.project.scan; 002 003 import javax.xml.bind.annotation.XmlElement; 004 import javax.xml.bind.annotation.XmlElementRef; 005 import javax.xml.bind.annotation.XmlElementRefs; 006 import javax.xml.bind.annotation.XmlType; 007 008 import edu.nrao.sss.astronomy.SkyPosition; 009 import edu.nrao.sss.astronomy.VelocityConvention; 010 import edu.nrao.sss.astronomy.VelocityFrame; 011 import edu.nrao.sss.measure.LinearVelocity; 012 import edu.nrao.sss.measure.LinearVelocityUnits; 013 014 /** 015 * A grouping of a sky position, radial velocity, and rest frame for 016 * specifying Doppler tracking information for a scan. 017 * <p> 018 * <b>Version Info:</b> 019 * <table style="margin-left:2em"> 020 * <tr><td>$Revision: 2102 $</td></tr> 021 * <tr><td>$Date: 2009-03-12 08:49:53 -0600 (Thu, 12 Mar 2009) $</td></tr> 022 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 023 * </table></p> 024 * 025 * @author David M. Harland 026 * @since 2008-09-10 027 */ 028 @XmlType(propOrder = {"position", "xmlVelocity"}) 029 030 public class ScanDopplerSpecs 031 implements Cloneable 032 { 033 private SkyPosition dtPosition; 034 private LinearVelocity dtVelocity; 035 private VelocityFrame dtRestFrame; 036 private VelocityConvention dtVelConv; 037 038 /** 039 * Creates a new specification with a <i>null</i> position and velocity. 040 */ 041 public ScanDopplerSpecs() 042 { 043 setPosition(null); 044 setVelocity(null, null, null); 045 } 046 047 /** 048 * Creates a new specification with the given properties. 049 * 050 * @param sourcePosition 051 * See {@link #setPosition(SkyPosition)}. 052 * 053 * @param sourceVelocity 054 * See {@link #setVelocity(LinearVelocity, VelocityFrame, VelocityConvention)}. 055 * 056 * @param restFrame 057 * See {@link #setVelocity(LinearVelocity, VelocityFrame, VelocityConvention)}. 058 * 059 * @param velocityConvention 060 * See {@link #setVelocity(LinearVelocity, VelocityFrame, VelocityConvention)}. 061 */ 062 public ScanDopplerSpecs(SkyPosition sourcePosition, 063 LinearVelocity sourceVelocity, 064 VelocityFrame restFrame, 065 VelocityConvention velocityConvention) 066 { 067 setPosition(sourcePosition); 068 setVelocity(sourceVelocity, restFrame, velocityConvention); 069 } 070 071 /** 072 * Sets the sky position to use when Doppler tracking. 073 * 074 * @param newPosition 075 * a position to use for Doppler tracking calculations. 076 * A value of <i>null</i> may be used as a signal to the scan 077 * to use the position of its source. 078 */ 079 public final void setPosition(SkyPosition newPosition) 080 { 081 dtPosition = newPosition; 082 } 083 084 /** 085 * Sets the source velocity to use when Doppler tracking. 086 * 087 * @param newVelocity 088 * a source velocity to use for Doppler tracking calculations. 089 * Note that this is only the radial velocity of a source relative 090 * to a frame of rest. It does not account for the motion of Earth. 091 * A value of <i>null</i> may be used as a signal to the scan 092 * to use the velocity of its source. 093 * 094 * @param newFrame 095 * the rest frame against which {@code newVelocity} is measured. 096 * 097 * @param newConvention 098 * the convention used to determine {@code newVelocity}. 099 * 100 * @throws IllegalArgumentException 101 * if exactly one of the parameters is <i>null</i>. 102 */ 103 public final void setVelocity(LinearVelocity newVelocity, 104 VelocityFrame newFrame, 105 VelocityConvention newConvention) 106 { 107 //Must either be all null or all non-null 108 if ((newVelocity == null && newFrame == null && newConvention == null) || 109 (newVelocity != null && newFrame != null && newConvention != null)) 110 { 111 dtVelocity = newVelocity; 112 dtRestFrame = newFrame; 113 dtVelConv = newConvention; 114 } 115 else 116 { 117 throw new IllegalArgumentException( 118 "The velocity, frame, and convention must either all be null or all be non-null."); 119 } 120 } 121 122 /** 123 * The sky position to use for Doppler tracking. 124 * The returned value may be <i>null</i>, which the scan will take 125 * as a signal to use the position of its source. 126 * 127 * @return the sky position to use for Doppler tracking. 128 */ 129 @XmlElementRefs 130 ( 131 { 132 @XmlElementRef(type=edu.nrao.sss.astronomy.SimpleSkyPosition.class), 133 @XmlElementRef(type=edu.nrao.sss.astronomy.EphemerisTable.class), 134 @XmlElementRef(type=edu.nrao.sss.astronomy.Orbit.class), 135 @XmlElementRef(type=edu.nrao.sss.astronomy.PolynomialPosition.class), 136 @XmlElementRef(type=edu.nrao.sss.astronomy.PolynomialPositionTable.class), 137 @XmlElementRef(type=edu.nrao.sss.astronomy.SolarSystemBodyPosition.class) 138 } 139 ) 140 public SkyPosition getPosition() { return dtPosition; } 141 142 /** 143 * The source velocity to use for Doppler tracking. 144 * The returned value may be <i>null</i>, which the scan will take 145 * as a signal to use the velocity of its source. 146 * <p> 147 * Note that the returned velocity is only that of the source with 148 * respect to its {@link #getRestFrame() rest frame}. It does 149 * <i>not</i> include the motion of Earth.</p> 150 * <p> 151 * If the returned value is <i>null</i>, the returned value of 152 * {@link #getRestFrame()} and {@link #getVelocityConvention()} 153 * will also be <i>null</i>.</p> 154 * 155 * @return the source velocity to use for Doppler tracking. 156 */ 157 public LinearVelocity getVelocity() { return dtVelocity; } 158 159 /** 160 * The velocity convention to use for the Doppler tracking velocity. 161 * The returned value may be <i>null</i>, which the scan will take 162 * as a signal to use the convention of its source's velocity. 163 * <p> 164 * If the returned value is <i>null</i>, the returned value of 165 * {@link #getVelocity()} and {@link #getRestFrame()} 166 * will also be <i>null</i>.</p> 167 * 168 * @return the velocity convention to use for Doppler tracking. 169 */ 170 public VelocityConvention getVelocityConvention() { return dtVelConv; } 171 172 /** 173 * The rest frame to use for the Doppler tracking velocity. 174 * The returned value may be <i>null</i>, which the scan will take 175 * as a signal to use the frame of its source's velocity. 176 * <p> 177 * If the returned value is <i>null</i>, the returned value of 178 * {@link #getVelocity()} and {@link #getVelocityConvention()} 179 * will also be <i>null</i>.</p> 180 * 181 * @return the rest frame to use for the Doppler tracking velocity. 182 */ 183 public VelocityFrame getRestFrame() { return dtRestFrame; } 184 185 //---------------------------------------------------------------------------- 186 // Special JAXB code for velocity in order to keep both null or both non-null 187 //---------------------------------------------------------------------------- 188 189 private static class DopplerVelocity 190 { 191 @XmlElement LinearVelocity radialVelocity; 192 @XmlElement VelocityFrame restFrame; 193 @XmlElement VelocityConvention velocityConvention; 194 195 DopplerVelocity() { } 196 197 DopplerVelocity(LinearVelocity v, VelocityFrame f, VelocityConvention c) 198 { 199 radialVelocity = v; 200 restFrame = f; 201 velocityConvention = c; 202 } 203 } 204 205 @XmlElement(name="velocity") 206 @SuppressWarnings("unused") 207 private DopplerVelocity getXmlVelocity() 208 { 209 return 210 (dtVelocity == null) ? null : new DopplerVelocity(dtVelocity, dtRestFrame, 211 dtVelConv); 212 } 213 214 @SuppressWarnings("unused") 215 private void setXmlVelocity(DopplerVelocity dv) 216 { 217 dtVelocity = dv.radialVelocity; 218 dtRestFrame = dv.restFrame; 219 dtVelConv = dv.velocityConvention; 220 221 //Velocity convention was not originally specified. When we added it 222 //we made it an optional element in the xml for backward compatibility. 223 //This means the xml could bring us legitimate velocity info w/ a null 224 //convention. We detect that here & override. 225 if (dv.velocityConvention == null && dtVelocity != null) 226 { 227 LinearVelocityUnits units = dtVelocity.getUnits(); 228 229 if (units.equals(LinearVelocityUnits.Z)) 230 dtVelConv = VelocityConvention.REDSHIFT; 231 else 232 dtVelConv = VelocityConvention.RADIO; 233 } 234 } 235 236 //============================================================================ 237 // 238 //============================================================================ 239 240 @Override 241 /** 242 * Returns a copy of this specification. 243 * <p> 244 * If anything goes wrong during the cloning procedure, 245 * a {@code RuntimeException} will be thrown.</p> 246 */ 247 public ScanDopplerSpecs clone() 248 { 249 ScanDopplerSpecs clone = null; 250 try 251 { 252 //This line takes care of the primitive & immutable fields properly 253 clone = (ScanDopplerSpecs)super.clone(); 254 255 clone.dtPosition = (this.dtPosition == null) ? null : this.dtPosition.clone(); 256 clone.dtVelocity = (this.dtVelocity == null) ? null : this.dtVelocity.clone(); 257 } 258 catch (Exception ex) 259 { 260 throw new RuntimeException(ex); 261 } 262 263 return clone; 264 } 265 266 @Override 267 public boolean equals(Object o) 268 { 269 //Quick exit if o is this 270 if (o == this) 271 return true; 272 273 //Quick exit if o is null 274 if (o == null) 275 return false; 276 277 //Quick exit if classes are different 278 if (!o.getClass().equals(this.getClass())) 279 return false; 280 281 ScanDopplerSpecs other = (ScanDopplerSpecs)o; 282 283 return 284 objectsAreEqual(this.dtRestFrame, other.dtRestFrame) && 285 objectsAreEqual(this.dtVelocity, other.dtVelocity ) && 286 objectsAreEqual(this.dtVelConv, other.dtVelConv ) && 287 objectsAreEqual(this.dtPosition, other.dtPosition ); 288 } 289 290 private boolean objectsAreEqual(Object thisOne, Object thatOne) 291 { 292 return (thisOne == null) ? (thatOne == null) : thisOne.equals(thatOne); 293 } 294 295 @Override 296 public int hashCode() 297 { 298 //Taken from the Effective Java book by Joshua Bloch. 299 //The constants 17 & 37 are arbitrary & carry no meaning. 300 int result = 17; 301 302 if (dtPosition != null) 303 result = 37 * result + dtPosition.hashCode(); 304 305 if (dtVelocity != null) 306 result = 37 * result + dtVelocity.hashCode(); 307 308 if (dtVelConv != null) 309 result = 37 * result + dtVelConv.hashCode(); 310 311 if (dtRestFrame != null) 312 result = 37 * result + dtRestFrame.hashCode(); 313 314 return result; 315 } 316 }