001 /** 002 * 003 */ 004 package org.wdssii.core; 005 006 import java.util.Date; 007 008 /** 009 * @author lakshman 010 * 011 */ 012 public class RadialSet extends DataType { 013 private final float elevation; 014 015 protected final Radial[] radials; 016 017 private final CPoint radarLocation; 018 019 private final CVector myUx; 020 021 private final CVector myUy; 022 023 private final CVector myUz; 024 025 private final float rangeToFirstGate; 026 027 /** 028 * {@inheritDoc} 029 * @param master 030 */ 031 public RadialSet(RadialSet master){ 032 super(master); 033 this.elevation = master.elevation; 034 this.radials = new Radial[ master.radials.length ]; 035 for (int i=0; i < radials.length; ++i){ 036 radials[i] = new Radial( master.radials[i] ); 037 } 038 this.radarLocation = master.radarLocation; 039 this.myUx = master.myUx; 040 this.myUy = master.myUy; 041 this.myUz = master.myUz; 042 this.rangeToFirstGate = master.rangeToFirstGate; 043 } 044 045 public RadialSet(float elevation, Location radarLoc, Date scanTime, 046 float rangeToFirstGate, 047 String typeName, Radial[] radials) { 048 super(radarLoc, scanTime, typeName); 049 this.radials = radials; 050 this.elevation = elevation; 051 this.rangeToFirstGate = rangeToFirstGate; 052 // set up the co-ordinate system 053 radarLocation = originLocation.getCPoint(); 054 myUz = radarLocation.minus(new CPoint(0, 0, 0)).unit(); 055 myUx = new CVector(0, 0, 1).crossProduct(myUz).unit(); 056 myUy = myUz.crossProduct(myUx); 057 } 058 059 public float getElevation() { 060 return elevation; 061 } 062 063 /** meters */ 064 public float getRangeToFirstGateKms() { 065 return rangeToFirstGate; 066 } 067 068 /** 069 * beamwidth of first radial, or 1 degree if there is no radial. 070 */ 071 public float getBeamWidth() { 072 if (radials.length > 0) 073 return getRadial(0).getBeamWidth(); 074 return 1; 075 } 076 077 /** 078 * nyquist of first radial, or 0 if there is no radial. 079 */ 080 public float getNyquist() { 081 if (radials.length > 0) 082 return getRadial(0).getNyquist(); 083 return 0; 084 } 085 086 /** 087 * mean azimuthal spacing of all radials. 088 */ 089 public float getAzimuthalSpacing() { 090 float as = 0; 091 for (Radial r : radials){ 092 as += r.getAzimuthalSpacing(); 093 } 094 float result = (radials.length <= 1)? as : (as / radials.length); 095 return result; 096 } 097 098 /** 099 * gatewidth of first radial, or 1 km if there is no radial. 100 */ 101 public float getGateWidthKms() { 102 if (radials.length > 0) 103 return getRadial(0).getGateWidthKms(); 104 return 1.0f; 105 } 106 107 /** 108 * number of gates of first radial, or 0 if there is no radial. 109 */ 110 public int getNumGates() { 111 if (radials.length > 0) 112 return getRadial(0).getNumGates(); 113 return 0; 114 } 115 116 public int getNumRadials() { 117 return radials.length; 118 } 119 120 public Location getRadarLocation() { 121 return originLocation; 122 } 123 124 public CPoint getRadarCPoint() { 125 return radarLocation; 126 } 127 128 public Radial[] getRadials() { 129 return radials; 130 } 131 132 public Radial getRadial(int index) { 133 return radials[index]; 134 } 135 136 /** @return 0 if vcp is unknown. */ 137 int getVCP() { 138 try { 139 return Integer.parseInt(getAttribute("vcp").toString()); 140 } catch (Exception e) { 141 // number format, null, etc. 142 return 0; 143 } 144 } 145 146 public double getRawValue(float az, float rn) { 147 Radial r = getRadial(az); 148 if (r == null) 149 return MissingData; 150 return r.getRawValue(rn); 151 } 152 153 /** 154 * a very slow implementation 155 * 156 * @see NormalizedRadialSet. 157 */ 158 public Radial getRadial(float az) { 159 // move backwards to get more recent radials first 160 for (int i = radials.length - 1; i >= 0; --i) { 161 Radial r = getRadial(i); 162 if (r.contains(az)) 163 return r; 164 } 165 return null; 166 } 167 168 public double getRawValue(Location loc) { 169 return getRawValue(loc.getCPoint()); 170 } 171 172 public double getRawValue(CPoint pt) { 173 // vector from radar location to point 174 // in earth-based co-ordinate system 175 CVector fromConeApex = pt.minus(radarLocation); 176 return getValueInConicalSpace(fromConeApex); 177 } 178 179 /** returns the location of this point in space. */ 180 public CPoint getLocation(int radialno, int gateno) { 181 return getRadial(radialno).getLocation(elevation, gateno, 182 radarLocation, myUx, myUy, myUz); 183 } 184 185 /** 186 * The CVector here should in a co-ordinate system where the radar location 187 * is the origin, and the z-axis is perpendicular to the earth's surface, 188 * and the y-axis is north-ward. 189 */ 190 public double getValueInConicalSpace(CVector v) { 191 if (radials.length == 0) 192 return MissingData; 193 194 Radial first = getRadial(0); 195 double norm = v.norm(); 196 double gw = first.getGateWidthKms(); 197 if (norm < gw) 198 return MissingData; // before first gate .. 199 200 // what is the elevation of this point? 201 double bw = first.getBeamWidth(); 202 double elev = Math.asin(v.dotProduct(myUz) / norm) * 180 / Math.PI; 203 double elev_diff = elev - elevation; 204 if (elev_diff > bw) 205 return MissingData; 206 207 // within this elevation ... 208 // find az (range approximately equals the norm) 209 CVector vxy = v.crossProduct(myUz); 210 double dotx = vxy.dotProduct(myUx); 211 double doty = vxy.dotProduct(myUy); 212 double az = 180 + Math.atan2(doty, dotx) * 180 / Math.PI; 213 az = Radial.normalizeAzimuth((float) az); 214 return getRawValue((float) az, (float) norm); 215 } 216 217 /** debugging output */ 218 public String toStringDB() { 219 String s = "RadialSet " + getTypeName() + " at " + elevation + " has " 220 + radials.length + " radials." + " the first:\n" 221 + getRadial(0).toStringDB() + super.toStringDB(); 222 return s; 223 } 224 225 }