001    /**
002     * 
003     */
004    package org.wdssii.core;
005    
006    import java.util.Arrays;
007    
008    /**
009     * @author lakshman
010     * 
011     */
012    public class Radial {
013            private float[] values;
014    
015            private final float startAzimuth;
016    
017            private final float beamWidth;
018    
019            private final float azimuthalSpacing;
020            
021            private final float nyquist;
022            
023            private final float gateWidth;
024    
025            private CVector unitVector;
026    
027            /** in degrees and kilometers. Does not copy array 
028             * @param ny 
029             * @param  */
030            public Radial(float startAz, float beamWidth,
031                            float azimuthalSpacing, float gateWidth,
032                            float nyquist, float[] values) {
033                    this.gateWidth = gateWidth;
034                    this.values = values;
035                    this.startAzimuth = startAz;
036                    this.beamWidth = beamWidth;
037                    this.azimuthalSpacing = azimuthalSpacing;
038                    this.nyquist = nyquist;
039            }
040    
041            /**
042             * Creates a completely separate copy of the data so that the master can change
043             * without affecting this value.
044             * @param radial
045             */
046            public Radial(Radial master) {
047                    this.values = Arrays.copyOf(master.values, master.values.length);
048                    this.startAzimuth = master.startAzimuth;
049                    this.beamWidth = master.beamWidth;
050                    this.azimuthalSpacing = master.azimuthalSpacing;
051                    this.nyquist = master.nyquist;
052                    this.gateWidth = master.gateWidth;
053                    this.unitVector = master.unitVector;
054            }
055    
056            /** puts the given angle in the range [0,360) */
057            public static float normalizeAzimuth(float az) {
058                    // in range [0,360)
059                    if (az < 0)
060                            az += 360;
061                    else if (az >= 360)
062                            az -= 360;
063                    return az;
064            }
065    
066            public boolean contains(float az) {
067                    // returns range [0,360)
068                    float diff = normalizeAzimuth(az - startAzimuth);
069                    return (diff < azimuthalSpacing);
070            }
071    
072            public float[] getValues() {
073                    return values;
074            }
075    
076            /** returns a completely separate copy of the array. */
077            public float[] getClonedValues() {
078                    float[] temp = new float[values.length];
079                    for (int i = 0; i < values.length; ++i)
080                            temp[i] = values[i];
081                    return temp;
082            }
083    
084            /** may not be normalized */
085            public float getStartAzimuth() {
086                    return startAzimuth;
087            }
088    
089            /**
090             * the end azimuth is not normalized in range [0,360) -- the rule instead is
091             * that the azimuth will be greater than the start azimuth.
092             */
093            public float getEndAzimuth() {
094                    return (startAzimuth + azimuthalSpacing);
095            }
096    
097            /**
098             * the mid azimuth is not normalized in range [0,360) -- the rule instead is
099             * that the azimuth will be greater than the start azimuth.
100             */
101            public float getMidAzimuth() {
102                    return (float) (startAzimuth + 0.5 * azimuthalSpacing);
103            }
104    
105            /** always positive */
106            public float getBeamWidth() {
107                    return beamWidth;
108            }
109            
110            public float getAzimuthalSpacing(){
111                    return azimuthalSpacing;
112            }
113    
114            /** in meters */
115            public float getGateWidthKms() {
116                    return gateWidth;
117            }
118    
119            public float getValue(int index) {
120                    return values[index];
121            }
122    
123            public int getNumGates() {
124                    return values.length;
125            }
126    
127            /** in m/s */
128            public float getNyquist(){
129                    return nyquist;
130            }
131            
132            /** range in kilometers. */
133            public double getRawValue(double range) {
134                    int i = (int) Math.round(range / gateWidth);
135                    if (i >= 0 && i < values.length)
136                            return values[i];
137                    else
138                            return DataType.MissingData;
139            }
140    
141            /**
142             * get the unit vector along the direction of this radial. This method will
143             * do the computation only on the first call, and return old values after
144             * that, so the elevation is not used after that.
145             */
146            public CVector getUnitVector(float elevation) {
147                    if (unitVector == null) {
148                            // unit vector in co-ordinate system tangential to
149                            // earth at the radar location.
150                            double angle_to_xdir = (90 - getMidAzimuth()) * Math.PI / 180.0;
151                            unitVector = new CVector(Math.cos(angle_to_xdir), Math
152                                            .sin(angle_to_xdir), Math.sin(elevation * Math.PI / 180.0))
153                                            .unit();
154                            return unitVector;
155                    }
156                    return unitVector;
157            }
158    
159            /*
160             * @param elevation of the RadialSet @param gateno of point @param radar
161             * location of radar @param ux x-axis of local co-ordinate system tangential
162             * to earth's surface at radar location
163             */
164            public CPoint getLocation(float elevation, int gateno, CPoint radar,
165                            CVector ux, CVector uy, CVector uz) {
166                    CVector disp = getUnitVector(elevation).multiply(
167                                    gateno * getGateWidthKms() );
168                    CVector disp_global = ux.multiply(disp.x).plus(uy.multiply(disp.y))
169                                    .plus(uz.multiply(disp.z));
170                    CPoint result = radar.plus(disp_global);
171                    return result;
172            }
173    
174            /** debugging output */
175            public String toStringDB() {
176                    String s = "Radial " + startAzimuth + " to " + getEndAzimuth() + " deg"
177                                    + " " + gateWidth + "km " + " first 10 values: \n";
178                    for (int i = 0; i < 10; ++i)
179                            s += getValue(i) + " ";
180                    return (s + "\n");
181            }
182    
183    }