001    package edu.nrao.sss.astronomy;
002    
003    import java.util.Date;
004    
005    import javax.xml.bind.annotation.XmlElement;
006    import javax.xml.bind.annotation.XmlRootElement;
007    
008    import edu.nrao.sss.measure.Distance;
009    import edu.nrao.sss.measure.Latitude;
010    import edu.nrao.sss.measure.Longitude;
011    
012    /**
013     * A very basic implementation of a {@link SkyPosition sky position}.
014     * <p>
015     * <b>Version Info:</b>
016     * <table style="margin-left:2em">
017     *   <tr><td>$Revision: 1156 $</td></tr>
018     *   <tr><td>$Date: 2008-03-12 11:43:13 -0600 (Wed, 12 Mar 2008) $</td></tr>
019     *   <tr><td>$Author: dharland $</td></tr>
020     * </table></p>
021     * 
022     * @author David M. Harland
023     * @since 2007-04-17
024     */
025    @XmlRootElement
026    public class SimpleSkyPosition
027      extends AbsSkyPos
028    {
029      private Longitude longitude;
030      private Latitude  latitude;
031      private Distance  distance;
032      
033      private Longitude longitudeUncertainty;
034      private Latitude  latitudeUncertainty;
035      private Distance  distanceUncertainty;
036      
037      /** Creates a new equatorial, J2000, position. */
038      public SimpleSkyPosition()
039      {
040        this(CelestialCoordinateSystem.EQUATORIAL, Epoch.J2000);
041      }
042      
043      /** Creates a new instance with the given properties. */
044      public SimpleSkyPosition(CelestialCoordinateSystem system, Epoch epoch)
045      {
046        super(system, epoch);
047        
048        longitude = new Longitude();
049        latitude  = new Latitude();
050        distance  = new Distance();
051        
052        longitudeUncertainty = new Longitude();
053        latitudeUncertainty  = new Latitude();
054        distanceUncertainty  = new Distance();
055      }
056      
057      @Override
058      public void reset()
059      {
060        super.reset();
061        
062        longitude.reset();
063        latitude.reset();
064        distance.reset();
065        
066        longitudeUncertainty.reset();
067        latitudeUncertainty.reset();
068        distanceUncertainty.reset();
069      }
070    
071      //============================================================================
072      // 
073      //============================================================================
074      
075      /* (non-Javadoc)
076       * @see SkyPosition#getType()
077       */
078      public SkyPositionType getType()  { return SkyPositionType.SIMPLE; }
079      
080      /* (non-Javadoc)
081       * @see edu.nrao.sss.astronomy.SkyPosition#isMoving()
082       */
083      public boolean isMoving()  { return false; }
084    
085      //============================================================================
086      // 
087      //============================================================================
088    
089      /**
090       * Sets the longitude of this position.
091       * <p>
092       * If {@code newLongitude} is <i>null</i>, this method creates, and saves a
093       * reference to, a new longitude object.  Otherwise it saves a reference
094       * to {@code newLongitude}.  This means that any changes made to
095       * (a non-null) {@code newLongitude} by clients after this call
096       * <i>will</i> be reflected in this position.</p> 
097       * 
098       * @param newLongitude a new longitude for this position.
099       */
100      public void setLongitude(Longitude newLongitude)
101      {
102        longitude = (newLongitude == null) ? new Longitude() : newLongitude;
103      }
104      
105      /**
106       * Returns the current longitude of this position.
107       * <p>
108       * The returned object is guaranteed to be non-null and is also a reference
109       * to the internal longitude held by this position.  This means any changes
110       * made by clients to the returned object will be reflected in this
111       * position.</p>
112       * 
113       * @return the current longitude of this position.
114       */
115      @XmlElement
116      @Override
117      public Longitude getLongitude()
118      {
119        return longitude;
120      }
121    
122      /**
123       * Sets the latitude of this position.
124       * <p>
125       * If {@code newLatitude} is <i>null</i>, this method creates, and saves a
126       * reference to, a new latitude object.  Otherwise it saves a reference
127       * to {@code newLatitude}.  This means that any changes made to
128       * (a non-null) {@code newLatitude} by clients after this call
129       * <i>will</i> be reflected in this position.</p> 
130       * 
131       * @param newLatitude a new latitude for this position.
132       */
133      public void setLatitude(Latitude newLatitude)
134      {
135        latitude = (newLatitude == null) ? new Latitude() : newLatitude;
136      }
137    
138      /**
139       * Returns the current latitude of this position.
140       * <p>
141       * The returned object is guaranteed to be non-null and is also a reference
142       * to the internal latitude held by this position.  This means any changes
143       * made by clients to the returned object will be reflected in this
144       * position.</p>
145       * 
146       * @return the current latitude of this position.
147       */
148      @XmlElement
149      @Override
150      public Latitude getLatitude()
151      { 
152        return latitude;
153      }
154    
155      /**
156       * Sets the distance of this position.
157       * <p>
158       * If {@code newDistance} is <i>null</i>, this method creates, and saves a
159       * reference to, a new distance object.  Otherwise it saves a reference
160       * to {@code newDistance}.  This means that any changes made to
161       * (a non-null) {@code newDistance} by clients after this call
162       * <i>will</i> be reflected in this position.</p> 
163       * 
164       * @param newDistance a new distance for this position.
165       */
166      public void setDistance(Distance newDistance)
167      {
168        distance = (newDistance == null) ? new Distance() : newDistance;
169      }
170    
171      /**
172       * Returns the current distance of this position.
173       * <p>
174       * The returned object is guaranteed to be non-null and is also a reference
175       * to the internal distance held by this position.  This means any changes
176       * made by clients to the returned object will be reflected in this
177       * position.</p>
178       * 
179       * @return the current distance of this position.
180       */
181      @XmlElement
182      @Override
183      public Distance getDistance()
184      {
185        return distance;
186      }
187    
188      //----------------------------------------------------------------------------
189      // Position at point in time
190      //----------------------------------------------------------------------------
191    
192      /**
193       * Returns the longitude of this position at the given point in time.
194       * <p>
195       * The returned object is guaranteed to be non-null and is also a reference
196       * to the internal longitude held by this position.  This means any changes
197       * made by clients to the returned object will be reflected in this
198       * position.</p>
199       * <p>
200       * Since this class has no concept of time, the value returned here will
201       * be the same as that returned by the corresponding no-argument method.</p>
202       * 
203       * @return the longitude of this position at the given point in time.
204       */
205      public Longitude getLongitude(Date time)
206      {
207        return longitude;
208      }
209      
210      /**
211       * Returns the latitude of this position at the given point in time.
212       * <p>
213       * The returned object is guaranteed to be non-null and is also a reference
214       * to the internal latitude held by this position.  This means any changes
215       * made by clients to the returned object will be reflected in this
216       * position.</p>
217       * <p>
218       * Since this class has no concept of time, the value returned here will
219       * be the same as that returned by the corresponding no-argument method.</p>
220       * 
221       * @return the latitude of this position at the given point in time.
222       */
223      public Latitude getLatitude(Date time)
224      {
225        return latitude;
226      }
227      
228      /**
229       * Returns the distance of this position at the given point in time.
230       * <p>
231       * The returned object is guaranteed to be non-null and is also a reference
232       * to the internal distance held by this position.  This means any changes
233       * made by clients to the returned object will be reflected in this
234       * position.</p>
235       * <p>
236       * Since this class has no concept of time, the value returned here will
237       * be the same as that returned by the corresponding no-argument method.</p>
238       * 
239       * @return the distance at the given point in time.
240       */
241      public Distance getDistance(Date time)
242      {
243        return distance;
244      }
245    
246      //----------------------------------------------------------------------------
247      // Uncertainties
248      //----------------------------------------------------------------------------
249    
250      /**
251       * Sets the uncertainty in the longitude of this position.
252       * <p>
253       * If {@code newUncertainty} is <i>null</i>, this method creates, and saves a
254       * reference to, a new longitude object.  Otherwise it saves a reference
255       * to {@code newUncertainty}.  This means that any changes made to
256       * (a non-null) {@code newUncertainty} by clients after this call
257       * <i>will</i> be reflected in this position.</p> 
258       * 
259       * @param newUncertainty a new value for the uncertainty of the longitude of
260       *                       this position.
261       */
262      public void setLongitudeUncertainty(Longitude newUncertainty)
263      {
264        longitudeUncertainty =
265          (newUncertainty == null) ? new Longitude() : newUncertainty;
266      }
267    
268      /**
269       * Returns the uncertainty in the longitude of this position.
270       * <p>
271       * The returned object is guaranteed to be non-null and is also a reference
272       * to the internal uncertainty held by this position.  This means any changes
273       * made by clients to the returned object will be reflected in this
274       * position.</p>
275       * 
276       * @return the uncertainty in the longitude of this position.
277       */
278      @XmlElement
279      @Override
280      public Longitude getLongitudeUncertainty()
281      {
282        return longitudeUncertainty;
283      }
284    
285      /**
286       * Sets the uncertainty in the latitude of this position.
287       * <p>
288       * If {@code newUncertainty} is <i>null</i>, this method creates, and saves a
289       * reference to, a new latitude object.  Otherwise it saves a reference
290       * to {@code newUncertainty}.  This means that any changes made to
291       * (a non-null) {@code newUncertainty} by clients after this call
292       * <i>will</i> be reflected in this position.</p> 
293       * 
294       * @param newUncertainty a new value for the uncertainty of the latitude of
295       *                       this position.
296       */
297      public void setLatitudeUncertainty(Latitude newUncertainty)
298      {
299        latitudeUncertainty =
300          (newUncertainty == null) ? new Latitude() : newUncertainty;
301      }
302      
303      /**
304       * Returns the uncertainty in the latitude of this position.
305       * <p>
306       * The returned object is guaranteed to be non-null and is also a reference
307       * to the internal uncertainty held by this position.  This means any changes
308       * made by clients to the returned object will be reflected in this
309       * position.</p>
310       * 
311       * @return the uncertainty in the latitude of this position.
312       */
313      @XmlElement
314      @Override
315      public Latitude getLatitudeUncertainty()
316      {
317        return latitudeUncertainty;
318      }
319    
320      /**
321       * Sets the uncertainty in the distance of this position.
322       * <p>
323       * If {@code newUncertainty} is <i>null</i>, this method creates, and saves a
324       * reference to, a new distance object.  Otherwise it saves a reference
325       * to {@code newUncertainty}.  This means that any changes made to
326       * (a non-null) {@code newUncertainty} by clients after this call
327       * <i>will</i> be reflected in this position.</p> 
328       * 
329       * @param newUncertainty a new value for the uncertainty of the distance of
330       *                       this position.
331       */
332      public void setDistanceUncertainty(Distance newUncertainty)
333      {
334        distanceUncertainty =
335          (newUncertainty == null) ? new Distance() : newUncertainty;
336      }
337    
338      /**
339       * Returns the uncertainty in the distance of this position.
340       * <p>
341       * The returned object is guaranteed to be non-null and is also a reference
342       * to the internal uncertainty held by this position.  This means any changes
343       * made by clients to the returned object will be reflected in this
344       * position.</p>
345       * 
346       * @return the uncertainty in the distance of this position.
347       */
348      @XmlElement
349      @Override
350      public Distance getDistanceUncertainty()
351      {
352        return distanceUncertainty;
353      }
354    
355      //============================================================================
356      // 
357      //============================================================================
358    
359      /**
360       * Creates and returns a new polynomial position whose time-zero values are
361       * the same as those of this position.
362       * The returned position has a default reference time and a default
363       * valid time interval.
364       * 
365       * @return a new polynomial position based on this position.
366       */
367      public PolynomialPosition toPolynomialPosition()
368      {
369        PolynomialPosition pp = new PolynomialPosition();
370        
371        pp.setCoordinateSystem(getCoordinateSystem());
372        pp.setEpoch(getEpoch());
373        
374        pp.setDistanceAtTimeZero(getDistance());
375        pp.setLongitudeAtTimeZero(getLongitude());
376        pp.setLatitudeAtTimeZero(getLatitude());
377    
378        pp.setDistanceUncertainty(getDistanceUncertainty());
379        pp.setLongitudeUncertainty(getLongitudeUncertainty());
380        pp.setLatitudeUncertainty(getLatitudeUncertainty());
381        
382        return pp;
383      }
384      
385      //============================================================================
386      // 
387      //============================================================================
388      
389      @Override
390      public String toString()
391      {
392        StringBuilder buff = appendTo(null).append(',');
393        
394        buff.append(longitude).append("+/-").append(longitudeUncertainty);
395        buff.append(',');
396        buff.append(latitude).append("+/-").append(latitudeUncertainty);
397        buff.append(',');
398        buff.append(distance).append("+/-").append(distanceUncertainty);
399        
400        return buff.toString();
401      }
402      
403      /**
404       *  Returns a copy of this sky position.
405       *  <p>
406       *  If anything goes wrong during the cloning procedure,
407       *  a {@code RuntimeException} will be thrown.</p>
408       */
409      @Override
410      public SimpleSkyPosition clone()
411      {
412        SimpleSkyPosition clone = null;
413    
414        try
415        {
416          //This line takes care of the primitive & immutable fields properly
417          clone = (SimpleSkyPosition)super.clone();
418          
419          clone.longitude = this.longitude.clone();
420          clone.latitude  = this.latitude.clone();
421          clone.distance  = this.distance.clone();
422          
423          clone.longitudeUncertainty = this.longitudeUncertainty.clone();
424          clone.latitudeUncertainty  = this.latitudeUncertainty.clone();
425          clone.distanceUncertainty  = this.distanceUncertainty.clone();
426        }
427        catch (Exception ex)
428        {
429          throw new RuntimeException(ex);
430        }
431        
432        return clone;
433      }
434      
435      /** Creates and returns a copy of the given sky position. */
436      static SimpleSkyPosition copy(SkyPosition original, Date time)
437      {
438        SimpleSkyPosition copy = new SimpleSkyPosition();
439        
440        copy.setCoordinateSystem(original.getCoordinateSystem());
441        copy.setEpoch(original.getEpoch());
442        
443        copy.setLatitude (original.getLatitude(time).clone());
444        copy.setLongitude(original.getLongitude(time).clone());
445        copy.setDistance (original.getDistance(time).clone());
446        
447        copy.setLatitudeUncertainty (original.getLatitudeUncertainty().clone());
448        copy.setLongitudeUncertainty(original.getLongitudeUncertainty().clone());
449        copy.setDistanceUncertainty (original.getDistanceUncertainty().clone());
450        
451        return copy;
452      }
453    
454      /** Returns <i>true</i> if {@code o} is equal to this position. */
455      @Override
456      public boolean equals(Object o)
457      {
458        //Quick exit if o is this
459        if (o == this)
460          return true;
461        
462        //Quick exit if super class determines not equal
463        if (!super.equals(o))
464          return false;
465        
466        //Super class determined o is non-null & of same class
467        SimpleSkyPosition other = (SimpleSkyPosition)o;
468        
469        //NOTE: Absence of origin of information here is intentional.
470    
471        return other.longitude.equals(this.longitude) &&
472               other.latitude.equals (this.latitude ) &&
473               other.distance.equals (this.distance ) &&
474    
475               other.longitudeUncertainty.equals(this.longitudeUncertainty) &&
476               other.latitudeUncertainty.equals (this.latitudeUncertainty ) &&
477               other.distanceUncertainty.equals (this.distanceUncertainty );
478      }
479    
480      /** Returns a hash code value for this position. */
481      @Override
482      public int hashCode()
483      {
484        //Taken from the Effective Java book by Joshua Bloch.
485        //The constants 17 & 37 are arbitrary & carry no meaning.
486        
487        //You MUST keep this method in synch with equals()
488        
489        int result = super.hashCode();
490    
491        result = 37 * result + longitude.hashCode();
492        result = 37 * result + latitude.hashCode();
493        result = 37 * result + distance.hashCode();
494    
495        result = 37 * result + longitudeUncertainty.hashCode();
496        result = 37 * result + latitudeUncertainty.hashCode();
497        result = 37 * result + distanceUncertainty.hashCode();
498        
499        return result;
500      }
501    }