多普勒天气雷达的体扫产品处理代码。
包含RadialImage.java、RadialImageBlock.java、RadialProductBlock.java三个类。
由SymbologyImage.java类判断产品为Symbology且特征码为AF1F时调用。
RadialImage.java
001 /**
002 * PACKAGE : cma.gmb.doppler
003 * FILENAME : RadialImage.java
004 * DESCRIPTION : 处理多普勒雷达产品数据(扫描产品Radial)
005 * AUTHOR : 刘泽军
006 * EMAIL : BJ0773@gmail.com
007 * Date : 2007-06-02 23:52:38
008 * Update : 2007-06-13 从SymbologyImage.java独立出来
009 * Reference : 《National Climatic Data Center DATA DOCUMENTATION FOR TD7000 -
010 * TD7599 NEXRAD LEVEL III》
011 *
012 * 注:部份代码参考了山东装备中心黄磊(stonehuang@126.com)的Pascal代码,特此声明并致谢。
013 *
014 */
015
016 package cma.gmb.doppler;
017
018 import java.io.*;
019 import java.awt.*;
020
021 import cma.common.dataio.*;
022 import cma.common.projection.*;
023 import cma.micaps.diamond.*;
024 import cma.gmb.doppler.datatype.*;
025
026 public class RadialImage {
027
028 //外部传入的数据
029 public MessageHeaderBlock messageHeaderBlock;
030 public ProductDescriptionBlock productDescriptionBlock;
031 public ProductSymbologyBlock productSymbologyBlock;
032 public ProductSymbologyLayerBlock productSymbologyLayerBlock;
033
034 //需要读取的数据
035 public RadialProductBlock radialProductBlock;
036 public RadialImageBlock[] radialImageBlock;
037
038 public static Color[] levels = {
039 new Color( 0, 0, 0), new Color( 0, 0,246), new Color( 1,159,246), new Color( 0,236,236),
040 new Color( 1,255, 0), new Color( 0,200, 0), new Color( 1,144, 0), new Color(255,255, 0),
041 new Color(231,192, 0), new Color(255,144, 0), new Color(254, 0, 0), new Color(214, 0, 0),
042 new Color(192, 0, 0), new Color(255, 0,250), new Color(174,144,240), new Color(255,255,255)
043 };
044
045 /**
046 * 功能:构造函数
047 * 参数:
048 * 无
049 * 返回值:
050 * 无
051 */
052 public RadialImage() {
053 }
054
055 /**
056 * 功能:读取Radial Image产品数据,不包括文件头信息,注意在调用前先定位好偏移量
057 * 参数:
058 * fin - 随机访问文件
059 * 返回值:
060 * 是否成功
061 */
062 public boolean read(RandomAccessFile fin) throws Exception {
063
064 if( !"AF1F".equalsIgnoreCase(productSymbologyLayerBlock.PacketCode) ) {//非扫描数据 Radial Image
065 return(false);
066 }
067 boolean ok = false;
068 radialProductBlock = new RadialProductBlock();
069 ok = radialProductBlock.read(fin);
070 if( ok && radialProductBlock.NumberOfRadials > 0 ) {
071 radialImageBlock = new RadialImageBlock[radialProductBlock.NumberOfRadials];
072 for(int i=0;i<radialProductBlock.NumberOfRadials;i++) {
073 radialImageBlock[i] = new RadialImageBlock();
074 ok = ok && radialImageBlock[i].read(fin);
075 }
076 }
077 return(ok);
078 }
079
080 /**
081 * 功能:读取Radial Image产品数据,不包括文件头信息,注意在调用前先定位好读取偏移。主要是考虑直接从 .tar.gz 中读取
082 * 参数:
083 * in - InputStream,注意不能使用 in.close() 方法,因为在函数外部可能还需要继续从 in 读数据
084 * 返回值:
085 * 是否成功
086 */
087 public boolean read(InputStream fin) throws Exception {
088
089 if( !"AF1F".equalsIgnoreCase(productSymbologyLayerBlock.PacketCode) ) {//非扫描数据 Radial Image
090 return(false);
091 }
092 boolean ok = false;
093 radialProductBlock = new RadialProductBlock();
094 ok = radialProductBlock.read(fin);
095 if( ok && radialProductBlock.NumberOfRadials > 0 ) {
096 radialImageBlock = new RadialImageBlock[radialProductBlock.NumberOfRadials];
097 for(int i=0;i<radialProductBlock.NumberOfRadials;i++) {
098 radialImageBlock[i] = new RadialImageBlock();
099 ok = ok && radialImageBlock[i].read(fin);
100 }
101 }
102 return(ok);
103 }
104
105 /**
106 * 功能:绘制雷达背景图(图形区域为640*480,雷达图形区域为480*480,雷达站点信息区域为160*480)
107 * 参数:
108 * z - 缩放系数
109 * g - 图形设备
110 * c - 雷达中心位置
111 * pc - 极圈
112 * agl - 径线间隔,非正值则不画径线
113 * bnd - 省市县边界
114 * 返回值:
115 * 是否成功
116 */
117 public boolean drawBackground(double z, Graphics2D g, Point c, boolean pc, double agl, boolean bnd) {
118 if( z <= 0.0 ) {
119 return(false);
120 }
121 try {
122 Polar polar = new Polar(c, 0.001*productDescriptionBlock.RadarLongitude, 0.001*productDescriptionBlock.RadarLatitude);
123 polar.setScale(1.0*z);
124 //以下两行改进线条的锯齿
125 RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
126 g.setRenderingHints(renderHints);
127
128 // g.setColor(Color.black);//背景色
129 // g.fillRect(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240*2), (int)(z*240*2));
130
131 g.setColor(Color.white);//雷达图形区域的边框颜色
132 g.drawRect(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240*2), (int)(z*240*2)-2);
133
134 if( bnd ) {//画行政边界
135 Coordinate coordinate = new Coordinate(polar);
136 Diamond09.drawBorderline(g, new Color(92,92,92), coordinate, "/GIMDR/gmiss/config/CountyMap.dat");
137 Diamond09.drawBorderline(g, new Color(160,160,160), coordinate, "/GIMDR/gmiss/config/ProvinceMap.dat");
138 }
139
140 if( pc ) {//画极圈
141 g.setColor(new Color(255,255,255));
142 for(int i=50;i<=200;i=i+50) {//每50公里画一个圈
143 g.drawArc(c.x-(int)(z*i), c.y-(int)(z*i), (int)(z*i)*2, (int)(z*i)*2, 0, 360);
144 }
145 g.drawArc(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240)*2, (int)(z*240)*2, 0, 360);//外圈240公里
146 }
147
148 if( agl >= 1.0 ) {//画极径
149 Point pos1, pos2;
150 for(double i=0.0;i<180.0;i=i+agl) {
151 pos1 = polar.getXY(z*240.0, 0.0+i);
152 pos2 = polar.getXY(z*240.0, 180.0+i);
153 g.drawLine(pos1.x, pos1.y, pos2.x, pos2.y);
154 }
155 }
156 return(true);
157 }
158 catch(Exception ex) {
159 System.out.println(ex.getMessage());
160 ex.printStackTrace();
161 return(false);
162 }
163 }
164
165 /**
166 * 功能:绘制雷达信息区域
167 * 参数:
168 * g - 图形设备
169 * m - 雷达信息区域左上角位置
170 * 返回值:
171 * 是否成功
172 */
173 public boolean drawInformation(Graphics2D g, Point m) {
174 //以下两行改进线条的锯齿
175 RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
176 g.setRenderingHints(renderHints);
177 g.setColor(Color.white);//信息区域的边框颜色
178 g.drawRect(m.x, m.y, 160, 479);//住处区域的边框
179 return(true);
180 }
181
182 /**
183 * 功能:绘制雷达产品图,根据不同类型分别调用相应的画图函数
184 * 参数:
185 * z - 缩放系数
186 * g - 图形设备
187 * c - 雷达中心位置
188 * 返回值:
189 * 是否成功
190 */
191 public boolean draw(double z, Graphics2D g, Point c) {
192 return(
193 z <= 0.0 ||
194 null == radialProductBlock ||
195 radialProductBlock.NumberOfRadials <= 0 ||
196 drawRadialImage(z, g, c)
197 );
198 }
199 /**
200 * 功能:绘制RadialImage扫描图像(采用多边形填充法代替弧形填充)
201 * 参数:
202 * z - 缩放系数
203 * g - 图形设备
204 * c - 雷达中心位置
205 * 返回值:
206 * 是否成功
207 */
208 public boolean drawRadialImage(double z, Graphics2D g, Point c) {
209
210 Polar polar = new Polar(c, 0.001*productDescriptionBlock.RadarLongitude, 0.001*productDescriptionBlock.RadarLatitude);
211 polar.setScale(1.0);
212 //背景
213 //以下两行改进线条的锯齿
214 RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
215 g.setRenderingHints(renderHints);
216
217 Point pos;
218 double rangeScaleFactor = 0.001 * (int)radialProductBlock.RangeScaleFactor;
219 Polygon p = new Polygon();
220 for(int i=0;i<radialProductBlock.NumberOfRadials;i++) {
221 int iRunCount = 0;
222 int iRunValue = 0;
223 int iColor = -1;
224 for(int j=0;j<radialImageBlock[i].NumberOfRadialRLE*2;j++) {
225 iRunValue = radialImageBlock[i].Data[j] >> 4 & 0xF;
226 iColor = radialImageBlock[i].Data[j] & 0xF;
227 if( iRunValue > 0 && iColor >= 0 && iColor < 15 && radialImageBlock[i].DeltaAngle > 0 ) {
228 g.setColor(RadialImage.levels[iColor]);
229 p.reset();//重置多边形为空
230 if( iRunCount == 0 ) {
231 p.addPoint(c.x, c.y);
232 }
233 else {
234 /*
235 //矩形填充
236 pos = polar.getXY(z*rangeScaleFactor*iRunCount, 0.1*radialImageBlock[index][i].StartAngle);
237 p.addPoint(pos.x, pos.y);
238 pos = polar.getXY(z*rangeScaleFactor*iRunCount, 0.1*(radialImageBlock[index][i].StartAngle+radialImageBlock[index][i].DeltaAngle-1));
239 p.addPoint(pos.x, pos.y);
240 */
241 for(double k=0.0;k<=0.1*radialImageBlock[i].DeltaAngle-0.1;k=k+0.01) {
242 pos = polar.getXY(z*rangeScaleFactor*iRunCount, 0.1*radialImageBlock[i].StartAngle+k);
243 p.addPoint(pos.x, pos.y);
244 }
245
246 }
247 /*
248 //矩形填充
249 pos = polar.getXY(z*rangeScaleFactor*(iRunCount+iRunValue), 0.1*(radialImageBlock[index][i].StartAngle+radialImageBlock[index][i].DeltaAngle-1));
250 p.addPoint(pos.x, pos.y);
251 pos = polar.getXY(z*rangeScaleFactor*(iRunCount+iRunValue), 0.1*radialImageBlock[index][i].StartAngle);
252 p.addPoint(pos.x, pos.y);
253 */
254 //多边形填充
255 for(double k=0.1*radialImageBlock[i].DeltaAngle-0.1;k>=0.0;k=k-0.01) {
256 pos = polar.getXY(z*rangeScaleFactor*(iRunCount+iRunValue), 0.1*radialImageBlock[i].StartAngle+k);
257 p.addPoint(pos.x, pos.y);
258 }
259
260 if( p.npoints >= 3 ) {
261 // p.addPoint(p.xpoints[0], p.ypoints[0]);
262 g.fillPolygon(p);//仅填充多边形内部
263 g.drawPolygon(p);//画多边形边框
264 }
265 }
266 iRunCount += iRunValue > 0 ? iRunValue : 0;
267 }
268 }
269 return(true);
270 }
271
272 }
RadialImageBlock.java
001 /**
002 * PACKAGE : cma.gmb.doppler.datatype
003 FILENAME : RadialImageBlock.java
004 * DESCRIPTION : 多普勒雷达产品数据结构(Radial格式)
005 * AUTHOR : 刘泽军
006 * EMAIL : BJ0773@gmail.com
007 * Date : 2007-06-02 03:47:35
008 * Update : 2007-06-12
009 * Reference : 《NEXRAD LEVEL II数据格式》中文版及英文版
010 */
011
012 package cma.gmb.doppler.datatype;
013
014 import java.io.*;
015 import java.lang.*;
016
017 import cma.common.dataio.*;
018
019 public class RadialImageBlock {//极坐标扫描图像数据
020
021 public static int SIZE = 6;
022
023 public short NumberOfRadialRLE;
024 public short StartAngle;
025 public short DeltaAngle;
026 public byte[] Data;
027
028 /**
029 * 功能:构造函数
030 * 参数:
031 * 无
032 * 返回:
033 * 无
034 */
035 public RadialImageBlock() {
036 }
037
038 /**
039 * 功能:从随机文件中读取数据,并进行BigEndian转换
040 * 参数:
041 * raf - 随机访问的文件对象
042 * 返回:
043 * 是否成功
044 */
045 public boolean read(RandomAccessFile raf) {
046 try {
047 byte[] buf = new byte[RadialImageBlock.SIZE];
048 int len = raf.read(buf);
049 boolean ok = len == RadialImageBlock.SIZE ? parse(buf, 0) : false;
050 if( ok && NumberOfRadialRLE > 0 ) {
051 Data = new byte[NumberOfRadialRLE*2];
052 len = raf.read(Data);
053 }
054 return(ok && len == NumberOfRadialRLE*2);
055 }
056 catch(Exception ex) {
057 return(false);
058 }
059 }
060
061 /**
062 * 功能:从输入流文件中读取数据,并进行BigEndian转换
063 * 参数:
064 * in - InputStream对象
065 * 返回:
066 * 是否成功
067 */
068 public boolean read(InputStream in) {
069 try {
070 byte[] buf = new byte[RadialImageBlock.SIZE];
071 int len = in.read(buf);
072 boolean ok = len == RadialImageBlock.SIZE ? parse(buf, 0) : false;
073 if( ok && NumberOfRadialRLE > 0 ) {
074 Data = new byte[NumberOfRadialRLE*2];
075 len = in.read(Data);
076 }
077 return(ok && len == NumberOfRadialRLE*2);
078 }
079 catch(Exception ex) {
080 return(false);
081 }
082 }
083
084 /**
085 * 功能:从缓冲区中读数据
086 * (在外部方法中,一次性读入所有数据,然后逐类分析数据)
087 * 参数:
088 * buf - 缓冲数据
089 * index - 偏移
090 * 返回:
091 * 正确读出的数据字节数
092 */
093 public int read(byte[] buf, int index) {
094 boolean ok = parse(buf, index);
095 if( ok && NumberOfRadialRLE > 0 && buf.length >= index+NumberOfRadialRLE*2 ) {
096 Data = new byte[NumberOfRadialRLE*2];
097 for(int i=0;i<NumberOfRadialRLE*2;i++) {
098 Data[i] = buf[index+i];
099 }
100 return(RadialImageBlock.SIZE+NumberOfRadialRLE*2);
101 }
102 return(0);
103 }
104
105 /**
106 * 功能:从缓冲区中分析出数据
107 * 参数:
108 * buf - 缓冲数据
109 * 返回:
110 * 是否成功
111 */
112 public boolean parse(byte[] buf) {
113 return(parse(buf, 0));
114 }
115
116 /**
117 * 功能:从缓冲区中分析出数据
118 * 参数:
119 * buf - 缓冲数据
120 * index - 偏移
121 * 返回:
122 * 是否成功
123 */
124 public boolean parse(byte[] buf, int index) {
125 NumberOfRadialRLE = DataConverterBE.getShort(buf, index+ 0);
126 StartAngle = DataConverterBE.getShort(buf, index+ 2);
127 DeltaAngle = DataConverterBE.getShort(buf, index+ 4);
128 return(true);
129 }
130
131 /**
132 * 功能:获得数据信息
133 * 参数:
134 * 无
135 * 返回:
136 * 数据信息
137 */
138 public String info() {
139 String msg =
140 "/nRadialImageBlock.SIZE = " + String.valueOf(RadialImageBlock.SIZE) +
141 "/n NumberOfRadialRLE = " + String.valueOf(NumberOfRadialRLE) +
142 "/n StartAngle = " + String.valueOf(StartAngle) +
143 "/n DeltaAngle = " + String.valueOf(DeltaAngle) +
144 "/n";
145 /* for(int i=0;i<NumberOfRadialRLE*2;i++) {
146 msg = msg + String.valueOf((new Byte(Data[i])).intValue()/16)+","+String.valueOf((new Byte(Data[i])).intValue()%16)+" ";
147 }
148 msg = msg + "/n";
149 */
150 return(msg);
151 }
152 /**
153 * 功能:打印数据,主要用于测试
154 * 参数:
155 * 无
156 * 返回:
157 * 无
158 */
159 public void print() {
160 System.out.println(info());
161 }
162
163 }
RadialProductBlock.java
001 /**
002 * PACKAGE : cma.gmb.doppler.datatype
003 FILENAME : RadialProductBlock.java
004 * DESCRIPTION : 多普勒雷达产品数据结构(Radial格式)
005 * AUTHOR : 刘泽军
006 * EMAIL : BJ0773@gmail.com
007 * Date : 2007-06-07 11:01:44
008 * Update :
009 * Reference : 《NEXRAD LEVEL II数据格式》中文版及英文版
010 */
011
012 package cma.gmb.doppler.datatype;
013
014 import java.io.*;
015 import java.lang.*;
016
017 import cma.common.dataio.*;
018
019 public class RadialProductBlock {//层数据包
020
021 public static int SIZE = 12;
022
023 public short IndexOfFirstRangeBin;
024 public short NumberOfRangeBins;
025 public short CenterOfSweepI;
026 public short CenterOfSweepJ;
027 public short RangeScaleFactor;
028 public short NumberOfRadials;
029
030 /**
031 * 功能:构造函数
032 * 参数:
033 * 无
034 * 返回:
035 * 无
036 */
037 public RadialProductBlock() {
038 }
039
040 /**
041 * 功能:从文件中读取数据,并进行BigEndian转换
042 * 参数:
043 * raf - 随机访问的文件对象
044 * 返回:
045 * 是否成功
046 */
047 public boolean read(RandomAccessFile raf) {
048 try {
049 byte[] buf = new byte[RadialProductBlock.SIZE];
050 int len = raf.read(buf);
051 return(len == RadialProductBlock.SIZE ? parse(buf, 0) : false);
052 }
053 catch(Exception ex) {
054 return(false);
055 }
056 }
057
058 /**
059 * 功能:从输入流文件中读取数据,并进行BigEndian转换
060 * 参数:
061 * in - InputStream对象
062 * 返回:
063 * 是否成功
064 */
065 public boolean read(InputStream in) {
066 try {
067 byte[] buf = new byte[RadialProductBlock.SIZE];
068 int len = in.read(buf);
069 return(len == RadialProductBlock.SIZE ? parse(buf, 0) : false);
070 }
071 catch(Exception ex) {
072 return(false);
073 }
074 }
075
076 /**
077 * 功能:从缓冲区中读数据
078 * (在外部方法中,一次性读入所有数据,然后逐类分析数据)
079 * 参数:
080 * buf - 缓冲数据
081 * index - 偏移
082 * 返回:
083 * 正确读出的数据字节数
084 */
085 public int read(byte[] buf, int index) {
086 return(parse(buf, index)?RadialProductBlock.SIZE:0);
087 }
088
089 /**
090 * 功能:从缓冲区中分析出数据
091 * 参数:
092 * buf - 缓冲数据
093 * 返回:
094 * 是否成功
095 */
096 public boolean parse(byte[] buf) {
097 return(parse(buf, 0));
098 }
099
100 /**
101 * 功能:从缓冲区中分析出数据
102 * 参数:
103 * buf - 缓冲数据
104 * index - 偏移
105 * 返回:
106 * 是否成功
107 */
108 public boolean parse(byte[] buf, int index) {
109 IndexOfFirstRangeBin = DataConverterBE.getShort(buf, index+ 0);
110 NumberOfRangeBins = DataConverterBE.getShort(buf, index+ 2);
111 CenterOfSweepI = DataConverterBE.getShort(buf, index+ 4);
112 CenterOfSweepJ = DataConverterBE.getShort(buf, index+ 6);
113 RangeScaleFactor = DataConverterBE.getShort(buf, index+ 8);
114 NumberOfRadials = DataConverterBE.getShort(buf, index+10);
115 return(true);
116 }
117
118 /**
119 * 功能:获得数据信息
120 * 参数:
121 * 无
122 * 返回:
123 * 数据信息
124 */
125 public String info() {
126 String msg =
127 "/nRadialProductBlock.SIZE = " + String.valueOf(RadialProductBlock.SIZE) +
128 "/n IndexOfFirstRangeBin = " + String.valueOf(IndexOfFirstRangeBin) +
129 "/n NumberOfRangeBins = " + String.valueOf(NumberOfRangeBins) +
130 "/n CenterOfSweepI = " + String.valueOf(CenterOfSweepI) +
131 "/n CenterOfSweepJ = " + String.valueOf(CenterOfSweepJ) +
132 "/n RangeScaleFactor = " + String.valueOf(RangeScaleFactor) +
133 "/n NumberOfRadials = " + String.valueOf(NumberOfRadials) +
134 "/n";
135 return(msg);
136 }
137
138 /**
139 * 功能:打印数据,主要用于测试
140 * 参数:
141 * 无
142 * 返回:
143 * 无
144 */
145 public void print() {
146 System.out.println(info());
147 }
148
149 }
包含RadialImage.java、RadialImageBlock.java、RadialProductBlock.java三个类。
由SymbologyImage.java类判断产品为Symbology且特征码为AF1F时调用。
RadialImage.java
001 /**
002 * PACKAGE : cma.gmb.doppler
003 * FILENAME : RadialImage.java
004 * DESCRIPTION : 处理多普勒雷达产品数据(扫描产品Radial)
005 * AUTHOR : 刘泽军
006 * EMAIL : BJ0773@gmail.com
007 * Date : 2007-06-02 23:52:38
008 * Update : 2007-06-13 从SymbologyImage.java独立出来
009 * Reference : 《National Climatic Data Center DATA DOCUMENTATION FOR TD7000 -
010 * TD7599 NEXRAD LEVEL III》
011 *
012 * 注:部份代码参考了山东装备中心黄磊(stonehuang@126.com)的Pascal代码,特此声明并致谢。
013 *
014 */
015
016 package cma.gmb.doppler;
017
018 import java.io.*;
019 import java.awt.*;
020
021 import cma.common.dataio.*;
022 import cma.common.projection.*;
023 import cma.micaps.diamond.*;
024 import cma.gmb.doppler.datatype.*;
025
026 public class RadialImage {
027
028 //外部传入的数据
029 public MessageHeaderBlock messageHeaderBlock;
030 public ProductDescriptionBlock productDescriptionBlock;
031 public ProductSymbologyBlock productSymbologyBlock;
032 public ProductSymbologyLayerBlock productSymbologyLayerBlock;
033
034 //需要读取的数据
035 public RadialProductBlock radialProductBlock;
036 public RadialImageBlock[] radialImageBlock;
037
038 public static Color[] levels = {
039 new Color( 0, 0, 0), new Color( 0, 0,246), new Color( 1,159,246), new Color( 0,236,236),
040 new Color( 1,255, 0), new Color( 0,200, 0), new Color( 1,144, 0), new Color(255,255, 0),
041 new Color(231,192, 0), new Color(255,144, 0), new Color(254, 0, 0), new Color(214, 0, 0),
042 new Color(192, 0, 0), new Color(255, 0,250), new Color(174,144,240), new Color(255,255,255)
043 };
044
045 /**
046 * 功能:构造函数
047 * 参数:
048 * 无
049 * 返回值:
050 * 无
051 */
052 public RadialImage() {
053 }
054
055 /**
056 * 功能:读取Radial Image产品数据,不包括文件头信息,注意在调用前先定位好偏移量
057 * 参数:
058 * fin - 随机访问文件
059 * 返回值:
060 * 是否成功
061 */
062 public boolean read(RandomAccessFile fin) throws Exception {
063
064 if( !"AF1F".equalsIgnoreCase(productSymbologyLayerBlock.PacketCode) ) {//非扫描数据 Radial Image
065 return(false);
066 }
067 boolean ok = false;
068 radialProductBlock = new RadialProductBlock();
069 ok = radialProductBlock.read(fin);
070 if( ok && radialProductBlock.NumberOfRadials > 0 ) {
071 radialImageBlock = new RadialImageBlock[radialProductBlock.NumberOfRadials];
072 for(int i=0;i<radialProductBlock.NumberOfRadials;i++) {
073 radialImageBlock[i] = new RadialImageBlock();
074 ok = ok && radialImageBlock[i].read(fin);
075 }
076 }
077 return(ok);
078 }
079
080 /**
081 * 功能:读取Radial Image产品数据,不包括文件头信息,注意在调用前先定位好读取偏移。主要是考虑直接从 .tar.gz 中读取
082 * 参数:
083 * in - InputStream,注意不能使用 in.close() 方法,因为在函数外部可能还需要继续从 in 读数据
084 * 返回值:
085 * 是否成功
086 */
087 public boolean read(InputStream fin) throws Exception {
088
089 if( !"AF1F".equalsIgnoreCase(productSymbologyLayerBlock.PacketCode) ) {//非扫描数据 Radial Image
090 return(false);
091 }
092 boolean ok = false;
093 radialProductBlock = new RadialProductBlock();
094 ok = radialProductBlock.read(fin);
095 if( ok && radialProductBlock.NumberOfRadials > 0 ) {
096 radialImageBlock = new RadialImageBlock[radialProductBlock.NumberOfRadials];
097 for(int i=0;i<radialProductBlock.NumberOfRadials;i++) {
098 radialImageBlock[i] = new RadialImageBlock();
099 ok = ok && radialImageBlock[i].read(fin);
100 }
101 }
102 return(ok);
103 }
104
105 /**
106 * 功能:绘制雷达背景图(图形区域为640*480,雷达图形区域为480*480,雷达站点信息区域为160*480)
107 * 参数:
108 * z - 缩放系数
109 * g - 图形设备
110 * c - 雷达中心位置
111 * pc - 极圈
112 * agl - 径线间隔,非正值则不画径线
113 * bnd - 省市县边界
114 * 返回值:
115 * 是否成功
116 */
117 public boolean drawBackground(double z, Graphics2D g, Point c, boolean pc, double agl, boolean bnd) {
118 if( z <= 0.0 ) {
119 return(false);
120 }
121 try {
122 Polar polar = new Polar(c, 0.001*productDescriptionBlock.RadarLongitude, 0.001*productDescriptionBlock.RadarLatitude);
123 polar.setScale(1.0*z);
124 //以下两行改进线条的锯齿
125 RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
126 g.setRenderingHints(renderHints);
127
128 // g.setColor(Color.black);//背景色
129 // g.fillRect(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240*2), (int)(z*240*2));
130
131 g.setColor(Color.white);//雷达图形区域的边框颜色
132 g.drawRect(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240*2), (int)(z*240*2)-2);
133
134 if( bnd ) {//画行政边界
135 Coordinate coordinate = new Coordinate(polar);
136 Diamond09.drawBorderline(g, new Color(92,92,92), coordinate, "/GIMDR/gmiss/config/CountyMap.dat");
137 Diamond09.drawBorderline(g, new Color(160,160,160), coordinate, "/GIMDR/gmiss/config/ProvinceMap.dat");
138 }
139
140 if( pc ) {//画极圈
141 g.setColor(new Color(255,255,255));
142 for(int i=50;i<=200;i=i+50) {//每50公里画一个圈
143 g.drawArc(c.x-(int)(z*i), c.y-(int)(z*i), (int)(z*i)*2, (int)(z*i)*2, 0, 360);
144 }
145 g.drawArc(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240)*2, (int)(z*240)*2, 0, 360);//外圈240公里
146 }
147
148 if( agl >= 1.0 ) {//画极径
149 Point pos1, pos2;
150 for(double i=0.0;i<180.0;i=i+agl) {
151 pos1 = polar.getXY(z*240.0, 0.0+i);
152 pos2 = polar.getXY(z*240.0, 180.0+i);
153 g.drawLine(pos1.x, pos1.y, pos2.x, pos2.y);
154 }
155 }
156 return(true);
157 }
158 catch(Exception ex) {
159 System.out.println(ex.getMessage());
160 ex.printStackTrace();
161 return(false);
162 }
163 }
164
165 /**
166 * 功能:绘制雷达信息区域
167 * 参数:
168 * g - 图形设备
169 * m - 雷达信息区域左上角位置
170 * 返回值:
171 * 是否成功
172 */
173 public boolean drawInformation(Graphics2D g, Point m) {
174 //以下两行改进线条的锯齿
175 RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
176 g.setRenderingHints(renderHints);
177 g.setColor(Color.white);//信息区域的边框颜色
178 g.drawRect(m.x, m.y, 160, 479);//住处区域的边框
179 return(true);
180 }
181
182 /**
183 * 功能:绘制雷达产品图,根据不同类型分别调用相应的画图函数
184 * 参数:
185 * z - 缩放系数
186 * g - 图形设备
187 * c - 雷达中心位置
188 * 返回值:
189 * 是否成功
190 */
191 public boolean draw(double z, Graphics2D g, Point c) {
192 return(
193 z <= 0.0 ||
194 null == radialProductBlock ||
195 radialProductBlock.NumberOfRadials <= 0 ||
196 drawRadialImage(z, g, c)
197 );
198 }
199 /**
200 * 功能:绘制RadialImage扫描图像(采用多边形填充法代替弧形填充)
201 * 参数:
202 * z - 缩放系数
203 * g - 图形设备
204 * c - 雷达中心位置
205 * 返回值:
206 * 是否成功
207 */
208 public boolean drawRadialImage(double z, Graphics2D g, Point c) {
209
210 Polar polar = new Polar(c, 0.001*productDescriptionBlock.RadarLongitude, 0.001*productDescriptionBlock.RadarLatitude);
211 polar.setScale(1.0);
212 //背景
213 //以下两行改进线条的锯齿
214 RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
215 g.setRenderingHints(renderHints);
216
217 Point pos;
218 double rangeScaleFactor = 0.001 * (int)radialProductBlock.RangeScaleFactor;
219 Polygon p = new Polygon();
220 for(int i=0;i<radialProductBlock.NumberOfRadials;i++) {
221 int iRunCount = 0;
222 int iRunValue = 0;
223 int iColor = -1;
224 for(int j=0;j<radialImageBlock[i].NumberOfRadialRLE*2;j++) {
225 iRunValue = radialImageBlock[i].Data[j] >> 4 & 0xF;
226 iColor = radialImageBlock[i].Data[j] & 0xF;
227 if( iRunValue > 0 && iColor >= 0 && iColor < 15 && radialImageBlock[i].DeltaAngle > 0 ) {
228 g.setColor(RadialImage.levels[iColor]);
229 p.reset();//重置多边形为空
230 if( iRunCount == 0 ) {
231 p.addPoint(c.x, c.y);
232 }
233 else {
234 /*
235 //矩形填充
236 pos = polar.getXY(z*rangeScaleFactor*iRunCount, 0.1*radialImageBlock[index][i].StartAngle);
237 p.addPoint(pos.x, pos.y);
238 pos = polar.getXY(z*rangeScaleFactor*iRunCount, 0.1*(radialImageBlock[index][i].StartAngle+radialImageBlock[index][i].DeltaAngle-1));
239 p.addPoint(pos.x, pos.y);
240 */
241 for(double k=0.0;k<=0.1*radialImageBlock[i].DeltaAngle-0.1;k=k+0.01) {
242 pos = polar.getXY(z*rangeScaleFactor*iRunCount, 0.1*radialImageBlock[i].StartAngle+k);
243 p.addPoint(pos.x, pos.y);
244 }
245
246 }
247 /*
248 //矩形填充
249 pos = polar.getXY(z*rangeScaleFactor*(iRunCount+iRunValue), 0.1*(radialImageBlock[index][i].StartAngle+radialImageBlock[index][i].DeltaAngle-1));
250 p.addPoint(pos.x, pos.y);
251 pos = polar.getXY(z*rangeScaleFactor*(iRunCount+iRunValue), 0.1*radialImageBlock[index][i].StartAngle);
252 p.addPoint(pos.x, pos.y);
253 */
254 //多边形填充
255 for(double k=0.1*radialImageBlock[i].DeltaAngle-0.1;k>=0.0;k=k-0.01) {
256 pos = polar.getXY(z*rangeScaleFactor*(iRunCount+iRunValue), 0.1*radialImageBlock[i].StartAngle+k);
257 p.addPoint(pos.x, pos.y);
258 }
259
260 if( p.npoints >= 3 ) {
261 // p.addPoint(p.xpoints[0], p.ypoints[0]);
262 g.fillPolygon(p);//仅填充多边形内部
263 g.drawPolygon(p);//画多边形边框
264 }
265 }
266 iRunCount += iRunValue > 0 ? iRunValue : 0;
267 }
268 }
269 return(true);
270 }
271
272 }
RadialImageBlock.java
001 /**
002 * PACKAGE : cma.gmb.doppler.datatype
003 FILENAME : RadialImageBlock.java
004 * DESCRIPTION : 多普勒雷达产品数据结构(Radial格式)
005 * AUTHOR : 刘泽军
006 * EMAIL : BJ0773@gmail.com
007 * Date : 2007-06-02 03:47:35
008 * Update : 2007-06-12
009 * Reference : 《NEXRAD LEVEL II数据格式》中文版及英文版
010 */
011
012 package cma.gmb.doppler.datatype;
013
014 import java.io.*;
015 import java.lang.*;
016
017 import cma.common.dataio.*;
018
019 public class RadialImageBlock {//极坐标扫描图像数据
020
021 public static int SIZE = 6;
022
023 public short NumberOfRadialRLE;
024 public short StartAngle;
025 public short DeltaAngle;
026 public byte[] Data;
027
028 /**
029 * 功能:构造函数
030 * 参数:
031 * 无
032 * 返回:
033 * 无
034 */
035 public RadialImageBlock() {
036 }
037
038 /**
039 * 功能:从随机文件中读取数据,并进行BigEndian转换
040 * 参数:
041 * raf - 随机访问的文件对象
042 * 返回:
043 * 是否成功
044 */
045 public boolean read(RandomAccessFile raf) {
046 try {
047 byte[] buf = new byte[RadialImageBlock.SIZE];
048 int len = raf.read(buf);
049 boolean ok = len == RadialImageBlock.SIZE ? parse(buf, 0) : false;
050 if( ok && NumberOfRadialRLE > 0 ) {
051 Data = new byte[NumberOfRadialRLE*2];
052 len = raf.read(Data);
053 }
054 return(ok && len == NumberOfRadialRLE*2);
055 }
056 catch(Exception ex) {
057 return(false);
058 }
059 }
060
061 /**
062 * 功能:从输入流文件中读取数据,并进行BigEndian转换
063 * 参数:
064 * in - InputStream对象
065 * 返回:
066 * 是否成功
067 */
068 public boolean read(InputStream in) {
069 try {
070 byte[] buf = new byte[RadialImageBlock.SIZE];
071 int len = in.read(buf);
072 boolean ok = len == RadialImageBlock.SIZE ? parse(buf, 0) : false;
073 if( ok && NumberOfRadialRLE > 0 ) {
074 Data = new byte[NumberOfRadialRLE*2];
075 len = in.read(Data);
076 }
077 return(ok && len == NumberOfRadialRLE*2);
078 }
079 catch(Exception ex) {
080 return(false);
081 }
082 }
083
084 /**
085 * 功能:从缓冲区中读数据
086 * (在外部方法中,一次性读入所有数据,然后逐类分析数据)
087 * 参数:
088 * buf - 缓冲数据
089 * index - 偏移
090 * 返回:
091 * 正确读出的数据字节数
092 */
093 public int read(byte[] buf, int index) {
094 boolean ok = parse(buf, index);
095 if( ok && NumberOfRadialRLE > 0 && buf.length >= index+NumberOfRadialRLE*2 ) {
096 Data = new byte[NumberOfRadialRLE*2];
097 for(int i=0;i<NumberOfRadialRLE*2;i++) {
098 Data[i] = buf[index+i];
099 }
100 return(RadialImageBlock.SIZE+NumberOfRadialRLE*2);
101 }
102 return(0);
103 }
104
105 /**
106 * 功能:从缓冲区中分析出数据
107 * 参数:
108 * buf - 缓冲数据
109 * 返回:
110 * 是否成功
111 */
112 public boolean parse(byte[] buf) {
113 return(parse(buf, 0));
114 }
115
116 /**
117 * 功能:从缓冲区中分析出数据
118 * 参数:
119 * buf - 缓冲数据
120 * index - 偏移
121 * 返回:
122 * 是否成功
123 */
124 public boolean parse(byte[] buf, int index) {
125 NumberOfRadialRLE = DataConverterBE.getShort(buf, index+ 0);
126 StartAngle = DataConverterBE.getShort(buf, index+ 2);
127 DeltaAngle = DataConverterBE.getShort(buf, index+ 4);
128 return(true);
129 }
130
131 /**
132 * 功能:获得数据信息
133 * 参数:
134 * 无
135 * 返回:
136 * 数据信息
137 */
138 public String info() {
139 String msg =
140 "/nRadialImageBlock.SIZE = " + String.valueOf(RadialImageBlock.SIZE) +
141 "/n NumberOfRadialRLE = " + String.valueOf(NumberOfRadialRLE) +
142 "/n StartAngle = " + String.valueOf(StartAngle) +
143 "/n DeltaAngle = " + String.valueOf(DeltaAngle) +
144 "/n";
145 /* for(int i=0;i<NumberOfRadialRLE*2;i++) {
146 msg = msg + String.valueOf((new Byte(Data[i])).intValue()/16)+","+String.valueOf((new Byte(Data[i])).intValue()%16)+" ";
147 }
148 msg = msg + "/n";
149 */
150 return(msg);
151 }
152 /**
153 * 功能:打印数据,主要用于测试
154 * 参数:
155 * 无
156 * 返回:
157 * 无
158 */
159 public void print() {
160 System.out.println(info());
161 }
162
163 }
RadialProductBlock.java
001 /**
002 * PACKAGE : cma.gmb.doppler.datatype
003 FILENAME : RadialProductBlock.java
004 * DESCRIPTION : 多普勒雷达产品数据结构(Radial格式)
005 * AUTHOR : 刘泽军
006 * EMAIL : BJ0773@gmail.com
007 * Date : 2007-06-07 11:01:44
008 * Update :
009 * Reference : 《NEXRAD LEVEL II数据格式》中文版及英文版
010 */
011
012 package cma.gmb.doppler.datatype;
013
014 import java.io.*;
015 import java.lang.*;
016
017 import cma.common.dataio.*;
018
019 public class RadialProductBlock {//层数据包
020
021 public static int SIZE = 12;
022
023 public short IndexOfFirstRangeBin;
024 public short NumberOfRangeBins;
025 public short CenterOfSweepI;
026 public short CenterOfSweepJ;
027 public short RangeScaleFactor;
028 public short NumberOfRadials;
029
030 /**
031 * 功能:构造函数
032 * 参数:
033 * 无
034 * 返回:
035 * 无
036 */
037 public RadialProductBlock() {
038 }
039
040 /**
041 * 功能:从文件中读取数据,并进行BigEndian转换
042 * 参数:
043 * raf - 随机访问的文件对象
044 * 返回:
045 * 是否成功
046 */
047 public boolean read(RandomAccessFile raf) {
048 try {
049 byte[] buf = new byte[RadialProductBlock.SIZE];
050 int len = raf.read(buf);
051 return(len == RadialProductBlock.SIZE ? parse(buf, 0) : false);
052 }
053 catch(Exception ex) {
054 return(false);
055 }
056 }
057
058 /**
059 * 功能:从输入流文件中读取数据,并进行BigEndian转换
060 * 参数:
061 * in - InputStream对象
062 * 返回:
063 * 是否成功
064 */
065 public boolean read(InputStream in) {
066 try {
067 byte[] buf = new byte[RadialProductBlock.SIZE];
068 int len = in.read(buf);
069 return(len == RadialProductBlock.SIZE ? parse(buf, 0) : false);
070 }
071 catch(Exception ex) {
072 return(false);
073 }
074 }
075
076 /**
077 * 功能:从缓冲区中读数据
078 * (在外部方法中,一次性读入所有数据,然后逐类分析数据)
079 * 参数:
080 * buf - 缓冲数据
081 * index - 偏移
082 * 返回:
083 * 正确读出的数据字节数
084 */
085 public int read(byte[] buf, int index) {
086 return(parse(buf, index)?RadialProductBlock.SIZE:0);
087 }
088
089 /**
090 * 功能:从缓冲区中分析出数据
091 * 参数:
092 * buf - 缓冲数据
093 * 返回:
094 * 是否成功
095 */
096 public boolean parse(byte[] buf) {
097 return(parse(buf, 0));
098 }
099
100 /**
101 * 功能:从缓冲区中分析出数据
102 * 参数:
103 * buf - 缓冲数据
104 * index - 偏移
105 * 返回:
106 * 是否成功
107 */
108 public boolean parse(byte[] buf, int index) {
109 IndexOfFirstRangeBin = DataConverterBE.getShort(buf, index+ 0);
110 NumberOfRangeBins = DataConverterBE.getShort(buf, index+ 2);
111 CenterOfSweepI = DataConverterBE.getShort(buf, index+ 4);
112 CenterOfSweepJ = DataConverterBE.getShort(buf, index+ 6);
113 RangeScaleFactor = DataConverterBE.getShort(buf, index+ 8);
114 NumberOfRadials = DataConverterBE.getShort(buf, index+10);
115 return(true);
116 }
117
118 /**
119 * 功能:获得数据信息
120 * 参数:
121 * 无
122 * 返回:
123 * 数据信息
124 */
125 public String info() {
126 String msg =
127 "/nRadialProductBlock.SIZE = " + String.valueOf(RadialProductBlock.SIZE) +
128 "/n IndexOfFirstRangeBin = " + String.valueOf(IndexOfFirstRangeBin) +
129 "/n NumberOfRangeBins = " + String.valueOf(NumberOfRangeBins) +
130 "/n CenterOfSweepI = " + String.valueOf(CenterOfSweepI) +
131 "/n CenterOfSweepJ = " + String.valueOf(CenterOfSweepJ) +
132 "/n RangeScaleFactor = " + String.valueOf(RangeScaleFactor) +
133 "/n NumberOfRadials = " + String.valueOf(NumberOfRadials) +
134 "/n";
135 return(msg);
136 }
137
138 /**
139 * 功能:打印数据,主要用于测试
140 * 参数:
141 * 无
142 * 返回:
143 * 无
144 */
145 public void print() {
146 System.out.println(info());
147 }
148
149 }