001 package edu.nrao.sss.model.project.scan; 002 003 import java.io.FileNotFoundException; 004 import java.io.Reader; 005 import java.util.ArrayList; 006 import java.util.List; 007 import java.util.SortedSet; 008 009 import javax.xml.bind.JAXBException; 010 import javax.xml.bind.annotation.XmlElement; 011 import javax.xml.bind.annotation.XmlElementWrapper; 012 import javax.xml.bind.annotation.XmlRootElement; 013 import javax.xml.stream.XMLStreamException; 014 015 import edu.nrao.sss.astronomy.CelestialCoordinateSystem; 016 import edu.nrao.sss.measure.TimeDuration; 017 import edu.nrao.sss.util.JaxbUtility; 018 019 /** 020 * A scan that holds a list of {@link PointingPosition pointing positions}. 021 * <p> 022 * <b>CVS Info:</b> 023 * <table style="margin-left:2em"> 024 * <tr><td>$Revision: 161 $</td></tr> 025 * <tr><td>$Date: 2006-12-15 11:48:34 -0700 (Fri, 15 Dec 2006) $</td></tr> 026 * <tr><td>$Author: btruitt $</td></tr> 027 * </table></p> 028 * 029 * @author David M. Harland 030 * @since 2006-07-10 031 */ 032 @XmlRootElement 033 public class PointingScan 034 extends Scan 035 { 036 private List<PointingPosition> positions; 037 private PositionType positionType; 038 private CelestialCoordinateSystem coordinateSystem; 039 040 /** Creates a new instance. */ 041 PointingScan() 042 { 043 super(); 044 045 positions = new ArrayList<PointingPosition>(); 046 positionType = PositionType.OFFSET; 047 coordinateSystem = CelestialCoordinateSystem.getDefault(); 048 } 049 050 /** 051 * Replaces this scan's list of positions with a list based on the given 052 * pattern. 053 * If the name is that of a standard pattern, this scan will be updated 054 * with pointing positions that emulate the pattern. Each position will 055 * have its duration set to {@code timeAtPosition}. If the name is 056 * not recognized this scan will contain an empty list of positions. 057 * <p> 058 * <b>Side Effects:</b> 059 * <ol> 060 * <li>This scan's celestial coordinate system will be 061 * updated to match that of the standard pattern. If the given name 062 * was not a standard pattern, the default coordinate system will be 063 * used.</li> 064 * <li>This scan's position type will be set to OFFSET.</li> 065 * </ol></p> 066 * 067 * @param nameOfStandardPattern the name of a standard NRAO pointing pattern. 068 * 069 * @param timeAtPosition the amount of time to spend at each position in the 070 * pattern. A <i>null</i> value will be treated as a 071 * duration of zero length. 072 * 073 * @see #getNamesOfStandardPatterns() 074 */ 075 public void setPositions(String nameOfStandardPattern, 076 TimeDuration timeAtPosition) 077 { 078 PointingPattern pp = PointingPattern.getPattern(nameOfStandardPattern); 079 080 if (pp != null) 081 { 082 //TODO get multiplier from Resource 083 setPositions(pp.makeOffsets(timeAtPosition, 1.0)); 084 setCoordinateSystem(pp.getCoordinateSystem()); 085 } 086 else 087 { 088 setPositions(null); 089 setCoordinateSystem(CelestialCoordinateSystem.getDefault()); 090 } 091 092 setPositionType(PositionType.OFFSET); 093 } 094 095 /** 096 * Sets the list of pointing positions held by this scan. 097 * A <i>null</i> {@code replacementList} will be interpreted 098 * as a new empty list. 099 * <p> 100 * This scan will hold a reference to {@code replacementList} 101 * (unless it is <i>null</i>), so any changes made to the list 102 * after calling this method will be reflected in this object.</p> 103 * 104 * @param replacementList a list of pointing positions to be held by this 105 * scan. 106 */ 107 public void setPositions(List<PointingPosition> replacementList) 108 { 109 positions = (replacementList == null) ? new ArrayList<PointingPosition>() 110 : replacementList; 111 } 112 113 /** 114 * Returns the list of pointing positions held by this scan. 115 * The returned list is guaranteed to be non-null, but may 116 * be empty. 117 * <p> 118 * The returned list is the actual list held by this scan, 119 * so changes made to the list will be reflected in this 120 * object.</p> 121 * 122 * @return the list of pointing positions held by this scan. 123 */ 124 @XmlElementWrapper 125 @XmlElement(name="pointingPosition") 126 public List<PointingPosition> getPositions() 127 { 128 return positions; 129 } 130 131 /** 132 * Sets the type of positions contained by this scan. 133 * The position type will be used for interpreting the contained positions 134 * as either absolute positions, or as positions that are offsets from this 135 * scan's central position. 136 * <p> 137 * If {@code posType} is <i>null</i>, it will be iterpreted as 138 * {@code PositionType.OFFSET}.</p> 139 * 140 * @param posType the type of positions contained by this scan. 141 */ 142 public void setPositionType(PositionType posType) 143 { 144 positionType = (posType == null) ? PositionType.OFFSET : posType; 145 } 146 147 /** 148 * Returns the type of positions contained by this scan. 149 * See {@link #setPositionType(PositionType)} for details. 150 * 151 * @return the type of positions contained by this scan. 152 */ 153 public PositionType getPositionType() 154 { 155 return positionType; 156 } 157 158 /** 159 * Sets the coordinate system for this scan. The coordinate system 160 * will be used for interpreting latitudinal and longitudinal values 161 * in the position elements. 162 * <p> 163 * If {@code system} is <i>null</i>, it will be iterpreted as 164 * the default coordinate system.</p> 165 * 166 * @param system the coordinate system for this scan. 167 */ 168 public void setCoordinateSystem(CelestialCoordinateSystem system) 169 { 170 coordinateSystem = 171 (system == null) ? CelestialCoordinateSystem.getDefault() : system; 172 } 173 174 /** 175 * Returns the coordinate system for this scan. 176 * See {@link #setCoordinateSystem(CelestialCoordinateSystem)} for 177 * details. 178 * 179 * @return the coordinate system for this scan. 180 */ 181 public CelestialCoordinateSystem getCoordinateSystem() 182 { 183 return coordinateSystem; 184 } 185 186 //============================================================================ 187 // TEXT 188 //============================================================================ 189 190 /* (non-Javadoc) 191 * @see edu.nrao.sss.model.project.scan.ScanLoopElement#toString() 192 */ 193 public String toSummaryString() 194 { 195 StringBuilder buff = new StringBuilder(super.toSummaryString()); 196 197 buff.append(", posType=").append(positionType); 198 buff.append(", coordSys=").append(coordinateSystem); 199 buff.append(", posCnt=").append(positions.size()); 200 201 return buff.toString(); 202 } 203 204 /** 205 * Creates a new scan from the XML data in the given file. 206 * 207 * @param xmlFile the name of an XML file. This method will attempt to locate 208 * the file by using {@link Class#getResource(String)}. 209 * 210 * @return a new scan from the XML data in the given file. 211 * 212 * @throws FileNotFoundException if the XML file cannot be found. 213 * 214 * @throws JAXBException if the schema file used (if any) is malformed, if 215 * the XML file cannot be read, or if the XML file is not 216 * schema-valid. 217 * 218 * @throws XMLStreamException if there is a problem opening the XML file, 219 * if the XML is not well-formed, or for some other 220 * "unexpected processing conditions". 221 */ 222 public static PointingScan fromXml(String xmlFile) 223 throws JAXBException, XMLStreamException, FileNotFoundException 224 { 225 return JaxbUtility.getSharedInstance() 226 .xmlFileToObject(xmlFile, PointingScan.class); 227 } 228 229 /** 230 * Creates a new scan based on the XML data read from {@code reader}. 231 * 232 * @param reader the source of the XML data. 233 * If this value is <i>null</i>, <i>null</i> is returned. 234 * 235 * @return a new scan based on the XML data read from {@code reader}. 236 * 237 * @throws XMLStreamException if the XML is not well-formed, 238 * or for some other "unexpected processing conditions". 239 * 240 * @throws JAXBException if anything else goes wrong during the 241 * transformation. 242 */ 243 public static PointingScan fromXml(Reader reader) 244 throws JAXBException, XMLStreamException 245 { 246 return JaxbUtility.getSharedInstance() 247 .readObjectAsXmlFrom(reader, PointingScan.class, null); 248 } 249 250 //============================================================================ 251 // 252 //============================================================================ 253 254 /** 255 * Returns a pointing scan that is a copy of this one. 256 * <p> 257 * The returned scan is, for the most part, a deep copy of this one. 258 * However, there are a few exceptions noted in the 259 * {@link ScanLoop#clone() clone method} of this class's parent.</p> 260 * <p> 261 * If anything goes wrong during the cloning procedure, 262 * a {@code RuntimeException} will be thrown.</p> 263 */ 264 public PointingScan clone() 265 { 266 PointingScan clone = null; 267 268 try 269 { 270 //This line takes care of the primitive & immutable fields properly 271 clone = (PointingScan)super.clone(); 272 273 //Need to clone set AND contained elements. 274 clone.positions = new ArrayList<PointingPosition>(); 275 for (PointingPosition pp : this.positions) 276 clone.positions.add(pp.clone()); 277 } 278 catch (Exception ex) 279 { 280 throw new RuntimeException(ex); 281 } 282 283 return clone; 284 } 285 286 /** 287 * Returns <i>true</i> if {@code o} is equal to this pointing scan. 288 * <p> 289 * In order for {@code o} to be equal to this scan, it must have 290 * equal pointing positions in the same order as those of this scan. 291 * It must also follow the rules set forth in the 292 * {@link ScanLoop#equals(Object) equals method} of this class's parent.</p> 293 */ 294 public boolean equals(Object o) 295 { 296 //Quick exit if o is this object 297 if (o == this) 298 return true; 299 300 //Not equal if super class says not equal 301 if (!super.equals(o)) 302 return false; 303 304 //Super class tested for Class equality, so cast is safe 305 PointingScan other = (PointingScan)o; 306 307 //Compare attributes 308 return other.positionType.equals(this.positionType) && 309 other.coordinateSystem.equals(this.coordinateSystem) && 310 other.positions.equals(this.positions); 311 } 312 313 /* (non-Javadoc) 314 * @see edu.nrao.sss.model.project.scan.Scan#hashCode() 315 */ 316 public int hashCode() 317 { 318 //Taken from the Effective Java book by Joshua Bloch. 319 //The constant 37 is arbitrary & carries no meaning. 320 int result = 37 * super.hashCode(); 321 322 result = 37 * result + positionType.hashCode(); 323 result = 37 * result + coordinateSystem.hashCode(); 324 result = 37 * result + positions.hashCode(); 325 326 return result; 327 } 328 329 //============================================================================ 330 // CLASS METHODS 331 //============================================================================ 332 333 /** 334 * Returns the names of NRAO's standard pointing patterns. 335 * @return the names of NRAO's standard pointing patterns. 336 */ 337 public static SortedSet<String> getNamesOfStandardPatterns() 338 { 339 return PointingPattern.getPatternNames(); 340 } 341 342 /** 343 * Creates a new pointing scan based on the given pattern name. 344 * If the name is that of a standard pattern, the returned scan will 345 * contain pointing positions that emulate the pattern. Each position will 346 * have its duration set to {@code timeAtPosition}. If the name is 347 * not recognized the returned scan will contain no positions. 348 * 349 * @param scanMode the observation mode for which a scan is desired. 350 * 351 * @param nameOfStandardPattern the name of a standard NRAO pointing pattern. 352 * 353 * @param timeAtPosition the amount of time to spend at each position in the 354 * pattern. A <i>null</i> value will be treated as a 355 * duration of zero length. 356 * 357 * @return a new pointing scan. 358 * 359 * @see #getNamesOfStandardPatterns() 360 */ 361 public static PointingScan create(ScanMode scanMode, 362 String nameOfStandardPattern, 363 TimeDuration timeAtPosition) 364 { 365 PointingScan result = null; 366 367 try 368 { 369 result = (PointingScan)Scan.createFor(scanMode); 370 } 371 catch (ClassCastException ex) 372 { 373 throw new IllegalArgumentException( 374 "Cannot make pointing scan for mode " + scanMode + 375 "; that mode gives class " + result.getClass().getSimpleName()); 376 } 377 378 result.setPositions(nameOfStandardPattern, timeAtPosition); 379 380 return result; 381 } 382 383 //============================================================================ 384 // 385 //============================================================================ 386 /* 387 public static void main(String[] args) 388 { 389 System.out.println(PointingScan.getNamesOfStandardPatterns()); 390 PointingScan scan = PointingScan.create(ScanMode.INTERFEROMETRIC_POINTING, 391 "Craig Cross", new TimeDuration(0.12)); 392 System.out.println(scan); 393 scan.setPositions("bogus", null); 394 System.out.println(scan); 395 scan.setPositions("Standard 5-Point", null); 396 System.out.println(scan); 397 } 398 */ 399 }