多普勒天气雷达的体扫产品处理代码。
包含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 }