001    package edu.nrao.sss.model.source;
002    
003    import java.util.Date;
004    
005    import edu.nrao.sss.astronomy.StokesParameter;
006    import edu.nrao.sss.measure.FluxDensity;
007    import edu.nrao.sss.measure.Frequency;
008    import edu.nrao.sss.measure.FrequencyRange;
009    import edu.nrao.sss.util.Filter;
010    
011    /**
012     * A filter that operates on {@link SourceBrightness} objects.
013     * <p>
014     * <b>Version Info:</b>
015     * <table style="margin-left:2em">
016     *   <tr><td>$Revision: 1616 $</td></tr>
017     *   <tr><td>$Date: 2008-10-10 14:25:31 -0600 (Fri, 10 Oct 2008) $</td></tr>
018     *   <tr><td>$Author: dharland $</td></tr>
019     * </table></p>
020     *  
021     * @author David M. Harland
022     * @since 2006-06-09
023     */
024    public class SourceBrightnessFilter
025      implements Filter<SourceBrightness>
026    {
027      //Wide-open valued for criteria
028      private static final Frequency       ANY_FREQUENCY    = null;
029      private static final FrequencyRange  ANY_FREQ_RANGE   = null;
030      private static final Date            ANY_TIME         = null;
031      private static final StokesParameter ANY_POLARIZATION = null;
032      
033      private static final FluxDensity NO_MIN_FLUX = new FluxDensity();
034      private static final FluxDensity NO_MAX_FLUX = new FluxDensity("+infinity");
035      
036      //Filtering criteria
037      private Frequency       frequency;
038      private FrequencyRange  freqRange;
039      private Date            time;
040      private StokesParameter polarization;
041      private FluxDensity     fluxMin;
042      private FluxDensity     fluxMax;
043      
044      /**
045       * Creates a new wide-open filter that allows all brightnesses to pass.
046       */
047      public SourceBrightnessFilter()
048      {
049        clearAll();
050      }
051      
052      /**
053       * Returns this filter to a wide-open state.
054       * After this call all filtering criteria will be in their wide-open
055       * states and this filter will allow all brightnesses to pass. 
056       */
057      public void clearAll()
058      {
059        clearFrequency();
060        clearTime();
061        clearPolarization();
062        clearFlux();
063      }
064      
065      /**
066       * Returns the flux density criterion to its wide-open state.
067       * 
068       * @see #setFlux(FluxDensity, FluxDensity)
069       * 
070       * @since 2008-07-29
071       */
072      public void clearFlux()
073      {
074        fluxMin = NO_MIN_FLUX;
075        fluxMax = NO_MAX_FLUX;
076      }
077      
078      /**
079       * Sets the flux density criterion of this filter to the given range.
080       * <p>
081       * <i>Null</i> values may be used to establish floors or ceilings.
082       * For example, to block all sources with a flux density less than
083       * <tt>F</tt> call: <tt>myFilter.setFlux(F, null);</tt>.</p>
084       * <p>
085       * Only those brightnesses whose
086       * {@link SourceBrightness#getPeakFluxDensity() flux densities}
087       * are in the range established here may pass through this filter.</p>
088       * 
089       * @param minimumFlux
090       *   the minimum flux density that may pass through this filter.
091       *   A value of <i>null</i> will be interpreted as a desire to
092       *   have no minimum value.
093       *   
094       * @param maximumFlux
095       *   the maximum flux density that may pass through this filter.
096       *   A value of <i>null</i> will be interpreted as a desire to
097       *   have no maximum value.
098       *   
099       * @see #clearFlux()
100       * 
101       * @since 2008-07-29
102       */
103      public void setFlux(FluxDensity minimumFlux, FluxDensity maximumFlux)
104      {
105        fluxMin = (minimumFlux == null) ? NO_MIN_FLUX : minimumFlux;
106        fluxMax = (maximumFlux == null) ? NO_MAX_FLUX : maximumFlux;
107      }
108      
109      /**
110       * Returns the frequency criterion to its wide-open state.
111       * 
112       * @see #setFrequency(Frequency)
113       */
114      public void clearFrequency()
115      {
116        clearFreq();
117        clearFreqRange();
118      }
119      
120      private void clearFreq()       { frequency = ANY_FREQUENCY;  }
121      private void clearFreqRange()  { freqRange = ANY_FREQ_RANGE; }
122      
123      /**
124       * Sets the frequency criterion of this filter to {@code newFrequency}.
125       * <p>
126       * Clients may choose to use this method to set a single frequency,
127       * or {@link #setFrequency(FrequencyRange)} to set a range of frequencies.
128       * When a single frequency is set, a match is deemed to occur when a
129       * source brightness's valid frequency range contains that single
130       * frequency.  When a range of frequencies is used, a match is deemed
131       * to occur whenever the valid range has any overlap with that range
132       * of frequencies.</p>
133       * <p>
134       * Calling this method always removes any previously set range
135       * of frequencies.
136       * If {@code newFrequency} is <i>null</i>, it will be interpreted as
137       * the desire to clear the single frequency as well.</p>
138       *  
139       * @param newFrequency the new frequency criterion for this filter.
140       * 
141       * @see #clearFrequency()
142       * @see #setFrequency(FrequencyRange)
143       */
144      public void setFrequency(Frequency newFrequency)
145      {
146        if (newFrequency == null)
147        {
148          clearFrequency();
149        }
150        else
151        {
152          clearFreqRange();
153          frequency = newFrequency;
154        }
155      }
156      
157      /**
158       * Sets the frequency criterion of this filter to {@code newRange}.
159       * <p>
160       * Clients may choose to use {@link #setFrequency(Frequency)} to set a
161       * single frequency, or this method to set a range of frequencies.
162       * When a single frequency is set, a match is deemed to occur when a
163       * source brightness's valid frequency range contains that single
164       * frequency.  When a range of frequencies is used, a match is deemed
165       * to occur whenever the valid range has any overlap with that range
166       * of frequencies.</p>
167       * <p>
168       * Calling this method always removes any previously set single frequency.
169       * If {@code newRange} is <i>null</i>, it will be interpreted as
170       * the desire to clear the range of frequencies as well.</p>
171       * 
172       * @param newRange the new frequency criterion for this filter.
173       * 
174       * @see #clearFrequency()
175       * @see #setFrequency(Frequency)
176       * 
177       * @since 2008-10-10
178       */
179      public void setFrequency(FrequencyRange newRange)
180      {
181        if (newRange == null)
182        {
183          clearFrequency();
184        }
185        else
186        {
187          clearFreq();
188          freqRange = newRange;
189        }
190      }
191      
192      /**
193       * Returns the time criterion to its wide-open state.
194       * 
195       * @see #setTime(Date)
196       */
197      public void clearTime()
198      {
199        time = ANY_TIME;
200      }
201      
202      /**
203       * Sets the time criterion of this filter to {@code newTime}.
204       * If {@code newTime} is <i>null</i>, it will be interpreted as
205       * the desire to clear the time criterion.
206       * <p>
207       * Only those brightnesses whose
208       * {@link SourceBrightness#getValidTime() valid time intervals}
209       * contain {@code newTime} may pass through this filter.</p>
210       *  
211       * @param newTime the new time criterion for this filter.
212       * 
213       * @see #clearTime()
214       */
215      public void setTime(Date newTime)
216      {
217        if (newTime == null)
218          clearTime();
219        else
220          time = newTime;
221      }
222      
223      /**
224       * Returns the polarization criterion to its wide-open state.
225       * 
226       * @see #setPolarization(StokesParameter)
227       */
228      public void clearPolarization()
229      {
230        polarization = ANY_POLARIZATION;
231      }
232      
233      /**
234       * Sets the polarization criterion of this filter to {@code newPolarization}.
235       * If {@code newPolarization} is <i>null</i>, it will be interpreted as
236       * the desire to clear the polarization criterion.
237       * <p>
238       * Only those brightnesses whose
239       * {@link SourceBrightness#getPolarization() polarizations}
240       * equal {@code newPolarization} may pass through this filter.</p>
241       *  
242       * @param newPolarization the new polarization criterion for this filter.
243       * 
244       * @see #clearPolarization()
245       */
246      public void setPolarization(StokesParameter newPolarization)
247      {
248        if (newPolarization == null)
249          clearPolarization();
250        else
251          polarization = newPolarization;
252      }
253      
254      /**
255       * Returns <i>true</i> if this filter blocks the given source brightness.
256       * <i>Null</i> brightnesses are always blocked.
257       * 
258       * @param sb the brightness to be filtered.
259       * 
260       * @return <i>true</i> if this filter blocks {@code sb}.
261       */
262      public boolean blocks(SourceBrightness sb)
263      {
264        //Filter blocks all null brightnesses
265        if (sb == null)
266          return true;
267        
268        //Block sb if it has wrong polarization (unless we don't
269        //want to filter on polarization)
270        if (polarization != ANY_POLARIZATION &&
271            !sb.getPolarization().equals(polarization))
272          return true;
273    
274        //Block sb if it doesn't contain our frequency (unless we don't
275        //want to filter on frequency)
276        if (frequency != ANY_FREQUENCY &&
277            !sb.getValidFrequency().contains(frequency))
278          return true;
279    
280        //Block sb if it doesn't overlap our frequency range (unless we don't
281        //want to filter on frequency)
282        if (freqRange != ANY_FREQ_RANGE &&
283            !sb.getValidFrequency().overlaps(freqRange))
284          return true;
285        
286        //Block sb if it doesn't contain our time (unless we don't
287        //want to filter on valid time)
288        if (time != ANY_TIME &&
289            !sb.getValidTime().contains(time))
290          return true;
291      
292        //Block sb if its flux density is not in the requested range
293        FluxDensity flux = sb.getPeakFluxDensity();
294        if (flux.compareTo(fluxMin) < 0 || flux.compareTo(fluxMax) > 0)
295          return true;
296        
297        //sb was not blocked
298        return false;
299      }
300      
301      /**
302       * Returns <i>true</i> if this filter allows the given source brightness
303       * to pass through it.
304       * <i>Null</i> brightnesses are always blocked.
305       * 
306       * @param sb the brightness to be filtered.
307       * 
308       * @return <i>true</i> if this filter allows {@code sb} to pass through it.
309       */
310      public boolean allows(SourceBrightness sb)
311      {
312        return !blocks(sb);
313      }
314    }