Polar(极坐标)投影--主要用于天气雷达图

13 篇文章 0 订阅
7 篇文章 0 订阅

Polar.java
001  /*
002 
003       Polar 投影(扫描方式,自正北方向顺时针)
004 
005          PACKAGE: cma.common.projection
006         FILENAME: Polar.java
007         LANGUAGE: Java2 v1.4
008         ORIGINAL: 无
009      DESCRIPTION: 极坐标投影(主要用于雷达图像处理)
010          RELATED: cma.common.projection.Lambert(兰勃特投影)
011           EDITOR: UltraEdit-32 v12.20a(Windows) NEdit(Linux)
012           CREATE: 2007-05-06 20:08:23
013           UPDATE: 2007-07-18 修改为抽象类Coordinate的扩展类
014           AUTHOR: 刘泽军 (BJ0773@gmail.com)
015                   广西气象减灾研究所
016                   Guangxi Institude of Meteorology and Disaster-reducing Research(GIMDR)
017 
018         Compile : javac Coordinate.java Polar.java
019 
020      How to use Polar class:
021 
022      Polar polar = new Polar(109.24, 24.35, 512, 384, 1.0, 0.0);//构造函数
023      ...
024 
025    */
026 
027  /**
028    *
029    *         扫描平面
030    *            /
031    *           /
032    *          /
033    *         /
034    *        /
035    *       /  仰角
036    *      -------------------- 0度平面
037    *
038    * 如图所示:
039    *          扫描平面=>0度平面,需要乘以cos(仰角)
040    *          0度平面=>扫描平面,需要除以cos(仰角)
041    *
042    * 注意,日常显示的雷达图是扫描平面上的图。本类所说的屏幕指扫描平面。
043    *
044    */
045 
046  /**
047    * 雷达扫描示意图
048    *
049    *                    359 0
050    *                        |     radius
051    *                        |       /
052    *                        |      /
053    *                        |angle/
054    *                        |    /
055    *                        | ^ /
056    *                        |  /
057    *                        | /
058    *                        |/
059    * 270 -----------------中心----------------- 90
060    *                        |
061    *                        |
062    *                        |
063    *                        |
064    *                        |
065    *                        |
066    *                        |
067    *                        |
068    *                        |
069    *                       180
070    */
071 
072  package  cma.common.projection;
073 
074  import  java.awt.*;
075  import  java.awt.geom.*;
076  import  java.lang.Math.*;
077 
078  public class  Polar  extends  Coordinate  {
079 
080       //私有成员
081       private  double   perKilometer        =  1.0 ;       //比例尺:一公里对应的像素点数(扫描平面)
082       private  double   elevation           =  0.0 ;       //仰角
083       private  double   cosineElevation     =  1.0 ;       //仰角的余弦值
084       private  double   kmPerDegreeX        =  1.0 ;       //1经度对应的距离(公里),不同纬度数值不同
085       private  double   kmPerDegreeY        =  1.0 ;       //1纬度对应的距离(公里),不同纬度数值不同
086 
087  /**
088    * 功能:计算球面上两点间的距离(单位:公里),原在edu.gimdr.Atmos.Meteorology类中写有,为避免import过多的类,故重写一份
089    * 参数:
090    *  lon1,lat1   - 第1点的位置(经纬度)
091    *  lon2,lat2   - 第2点的位置(经纬度)
092    * 返回值:
093    *      球面距离
094    */
095       public static  double  distanceOfSphere ( double  lon1,  double  lat1,  double  lon2,  double  lat2 ) {
096           /*  公式:
097               A(x,y)  B(a,b)
098               AB点的球面距离=R*{arccos[cos(b)*cos(y)*cos(a-x)+sin(b)*sin(y)]}, by Google
099           */
100 
101           double   rlon1   = Math.toRadians ( lon1 ) ;
102           double   rlat1   = Math.toRadians ( lat1 ) ;
103           double   rlon2   = Math.toRadians ( lon2 ) ;
104           double   rlat2   = Math.toRadians ( lat2 ) ;
105 
106           return ( Coordinate.RADIUS* ( Math.acos ( Math.cos ( rlat2 ) *Math.cos ( rlat1 ) *Math.cos ( rlon2-rlon1 ) +Math.sin ( rlat2 ) *Math.sin ( rlat1 )))) ;
107       }
108 
109  /**
110    * 功能:
111    *      重置参数
112    * 参数:
113    *      lon,lat     - 中心经纬度,
114    *      px,py       - 中心经纬度对应的屏幕坐标
115    *      sc          - 缩放系数
116    *      agl         - 仰角
117    * 返回值:
118    *      无
119    */
120       public  void  reset ( double  lon,  double  lat,  int  px,  int  py,  double  sc,  double  agl ) {
121           type        = Coordinate.POLAR;
122           center          =  new  Point2D.Double (
123                               lon <    0.0  ?    0.0  : lon >  360.0  360.0  : lon,
124                               lat < - 90.0  ? - 90.0  : lat >   90.0  ?   90.0  : lat
125                           ) ;
126           place           =  new  Point ( px, py ) ;
127           elevation       = Math.toRadians ( Math.IEEEremainder ( Math.abs ( agl ) 90.0 )) ; //在0-90度之间,但不能为90度
128           cosineElevation = Math.cos ( elevation ) ; //仰角的余弦值
129           scale           = sc ==  0.0  1.0  : Math.abs ( sc ) ; //缩放系数
130           scaleOriginal   = scale;
131           offset          =  new  Point ( 0 0 ) ;
132 
133           perKilometer    =  1.0 ; //标准比例尺
134           //中心经纬度或仰角发生改变,必须重新计算经向和纬向的1度对应的球面距离
135           kmPerDegreeX    = distanceOfSphere ( center.x, center.y, center.x+ 1.0 , center.y / cosineElevation;
136           kmPerDegreeY    = distanceOfSphere ( center.x, center.y, center.x, center.y+ 1.0 / cosineElevation;
137       }
138 
139  /**
140    * 功能:构造函数
141    * 参数:
142    *      lon     - 中心对应的经度坐标
143    *      lat     - 中心对应的纬度坐标
144    *      x       - 中心对应的屏幕位置x
145    *      y       - 中心对应的屏幕位置y
146    *      sc      - 缩放系数
147    * 返回值:
148    *      无
149    */
150       public  Polar ( double  lon,  double  lat,  int  x,  int  y,  double  sc ) {
151           reset ( lon, lat, x, y, sc,  0.0 ) ;
152       }
153 
154  /**
155    * 功能:构造函数
156    * 参数:
157    *      lon     - 中心对应的经度坐标
158    *      lat     - 中心对应的纬度坐标
159    *      x       - 中心对应的屏幕位置x
160    *      y       - 中心对应的屏幕位置y
161    *      sc      - 缩放系数
162    *      agl     = 仰角
163    * 返回值:
164    *      无
165    */
166       public  Polar ( double  lon,  double  lat,  int  x,  int  y,  double  sc,  double  agl ) {
167           reset ( lon, lat, x, y, sc, agl ) ;
168       }
169 
170  /**
171    * 功能:获得仰角
172    * 参数:
173    *      无
174    * 返回值:
175    *      仰角的度数
176    */
177       public  double  getElevation () {
178           return ( Math.toDegrees ( elevation )) ;
179       }
180 
181  /**
182    * 功能:获得经纬度对应的屏幕像素坐标,与雷达仰角有关,主要用于体扫数据显示、底图叠加等。
183    * 参数:
184    *      lon - 经度
185    *      lat - 纬度
186    * 返回值:
187    *      对应的屏幕坐标
188    */
189       public  Point getPosition ( double  lon,  double  lat ) {
190           double   disX    = distanceOfSphere ( lon, center.y, center.x, center.y ) /cosineElevation;
191           double   disY    = distanceOfSphere ( center.x, lat, center.x, center.y ) /cosineElevation;
192           double   x       =   ( lon>center.x? 1 :- 1 ) * ( disX*perKilometer*scale + place.x +  0.5 ;
193           double   y       = - ( lat>center.y? 1 :- 1 ) * ( disY*perKilometer*scale + place.y +  0.5 ;
194           return ( new  Point (( int ) x, ( int ) y )) ;
195       }
196 
197  /**
198    * 功能:获得极坐标对应的屏幕像素坐标,与雷达仰角无关,主要用于体扫数据显示、底图叠加等。
199    * 参数:
200    *      radius      - 极半径
201    *      angle       - 角度(以正北方向顺时针)
202    * 返回值:
203    *      对应的屏幕坐标
204    */
205 
206       public  Point getXY ( double  radius,  double  angle ) {
207           int  x   =  ( int )( 0.5  + radius * Math.sin ( Math.toRadians ( angle ))) ;
208           int  y   =  ( int )( 0.5  + radius * Math.cos ( Math.toRadians ( angle ))) ;
209           return ( new  Point ( place.x+x, place.y-y )) ;
210       }
211 
212  /**
213    * 功能:获得屏幕像素点位置的极坐标半径,由于是输入参数是扫描平面上的值,故与雷达仰角无关。
214    * 参数:
215    *      x   - 水平坐标
216    *      y   - 垂直坐标
217    * 返回值:
218    *      与极坐标中心的距离,即极半径
219    */
220       public  double  getRadius ( int  x,  int  y ) {
221           return ( Math.sqrt ( 1.0 * ( x-place.x ) * ( x-place.x ) + 1.0 * ( y-place.y ) * ( y-place.y ))) ;
222       }
223 
224  /**
225    * 功能:获得经纬度位置的极坐标半径,与雷达仰角有关。
226    * 参数:
227    *      lon - 经度坐标
228    *      lat - 纬度坐标
229    * 返回值:
230    *      与极坐标中心的距离(象素点),即极半径
231    */
232       public  double  getRadius ( double  lon,  double  lat ) {
233           Point   pos = getPosition ( lon, lat ) ; //此函数已经考虑了仰角的影响
234           return ( getRadius ( pos.x, pos.y )) ;
235       }
236 
237  /**
238    * 功能:获得屏幕像素点位置的极坐标角度(扫描平面与0度平面均相同),与雷达仰角无关。
239    * 参数:
240    *      x   - 水平坐标
241    *      y   - 垂直坐标
242    * 返回值:
243    *      角度值,自正北方向顺时针
244    */
245       public  double  getAngle ( int  x,  int  y ) {
246           double   agl =  0.0 ;
247           if x == place.x && y == place.y  ) { //重合
248               agl =  0.0 ;
249           }
250           else if x == place.x  ) {
251               agl = y > place.y ?  180.0  360.0 ;
252           }
253           else if y == place.y  ) {
254               agl = x > place.x ?  90.0  270.0 ;
255           }
256           else  {
257               agl = Math.toDegrees ( Math.atan ( 1.0 *Math.abs ( x-place.x ) /Math.abs ( y-place.y ))) ;
258               agl =
259                       x > place.x && y < place.y ? agl :           //直角坐标的第一象限
260                       x < place.x && y < place.y ?  180.0  - agl :   //直角坐标的第二象限
261                       x < place.x && y > place.y ?  180.0  + agl :   //直角坐标的第三象限
262                       x > place.x && y > place.y ?  360.0  - agl :   //直角坐标的第四象限
263                       agl;
264           }
265           System.out.println ( agl ) ;
266           return ( agl ) ;
267       }
268 
269  /**
270    * 功能:获得经纬度位置的极坐标角度(扫描平面与0度平面均相同),与雷达仰角无关。
271    * 参数:
272    *      lon - 水平坐标
273    *      lat - 垂直坐标
274    * 返回值:
275    *      角度值,自正北方向顺时针
276    */
277       public  double  getAngle ( double  lon,  double  lat ) {
278  /*
279  //若通过获得屏幕坐标来计算角度,精度比较差,特别是在极坐标中心附近
280           Point   p   = getPosition(lon, lat);
281           return(getAngle(p.x, p.y);
282  */
283           double   agl =  0.0 ;
284           if lon == center.x && lat == center.y  ) { //重合
285               agl =  0.0 ;
286           }
287           else if lon == center.x  ) {
288               agl = lat > center.y ?  360.0  180.0 ;
289           }
290           else if lat == center.y  ) {
291               agl = lon > center.x ?  90.0  270.0 ;
292           }
293           else  {
294               //注:由于经向和纬向的球面距离不等(华南,经向>纬向),故点(1,1)与中心点(0,0)的极角不等45度,而应是略大于45度
295               agl = Math.toDegrees ( Math.atan (( Math.abs ( lon-center.x ) *kmPerDegreeX ) / ( Math.abs ( lat-center.y ) *kmPerDegreeY ))) ;
296               agl =
297                       lon > center.x && lat > center.y ? agl :             //第一象限
298                       lon < center.x && lat > center.y ?  180.0  - agl :     //第二象限
299                       lon < center.x && lat < center.y ?  180.0  + agl :     //第三象限
300                       lon > center.x && lat < center.y ?  360.0  - agl :     //第四象限
301                       agl;
302           }
303           return ( agl ) ;
304       }
305 
306  /**
307    * 功能:
308    *      获得屏幕坐标对应的经纬度
309    * 参数:
310    *      x       - 屏幕水平坐标
311    *      y       - 屏幕垂直坐标
312    * 返回值:
313    *      对应的经纬度
314    */
315       public  Point2D.Double getCoordinate ( int  x,  int  y ) {
316           double   lat         = Math.toDegrees ( Math.toRadians ( center.y ( place.y-y ) *cosineElevation/perKilometer/scale/Polar.RADIUS ) ;
317           double   disX0       = distanceOfSphere ( center.x, lat, center.x+ 1.0 , lat ) ; //0度平面上1经度的球面距离
318           double   disX        = disX0 / cosineElevation;       //扫描平面上1经度的距离
319           double   perDegreeX  = disX * perKilometer * scale;           //扫描平面上1经度的对应的像素点数
320           double   lon         = center.x +  ( x - place.x / perDegreeX;
321           return ( new  Point2D.Double ( lon, lat )) ;
322       }
323 
324  /**
325    * 功能:
326    *      画经线、纬线
327    * 参数:
328    *      g       - 图形设备
329    *      f       - 字体
330    *      c       - 画线颜色
331    *      inc_lon - 经线间隔//未使用
332    *      inc_lat - 纬线间隔//未使用
333    * 返回值:
334    *      无
335    */
336       public  void  drawGridLine ( Graphics2D g, Font f, Color c,  int  inc_lon,  int  inc_lat ) {
337           Color   saveColor   = g.getColor () ;
338           Font    saveFont    = g.getFont () ;
339 
340           //以下两行改进线条的锯齿
341           //RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
342           //g.setRenderingHints(renderHints);
343 
344  //      g.setColor(Color.black);//背景色
345  //      g.fillRect(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240*2), (int)(z*240*2));
346 
347           g.setColor ( c ) ; //雷达图形区域的边框颜色
348           g.drawRect (( int )( 0.5 +place.x-scale* 240 ) ( int )( 0.5 +place.y-scale* 240 ) ( int )( 0.5 +scale* 240 * 2 ) ( int )( 0.5 +scale* 240 * 2 )) ;
349 
350           //画极径
351           Point   pos1, pos2;
352           for ( double  i= 0.0 ;i< 180.0 ;i=i+ 30.0 ) {
353               pos1    = getXY ( scale* 240.0 ,    0.0 +i ) ;
354               pos2    = getXY ( scale* 240.0 180.0 +i ) ;
355               g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;
356           }
357 
358           //画极圈
359           for ( int  i= 50 ;i<= 200 ;i=i+ 50 ) { //每50公里画一个圈
360               g.drawArc (( int )( 0.5 +place.x-scale*i ) ( int )( 0.5 +place.y-scale*i ) ( int )( 0.5 +scale*i* 2 ) ( int )( 0.5 +scale*i* 2 ) 0 360 ) ;
361           }
362           g.drawArc (( int )( 0.5 +place.x-scale* 240 ) ( int )( 0.5 +place.y-scale* 240 ) ( int )( 0.5 +scale* 240 * 2 ) ( int )( 0.5 +scale* 240 * 2 ) 0 360 ) ; //外圈240公里
363 
364           g.setFont ( saveFont ) ;
365           g.setColor ( saveColor ) ;
366       }
367  }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值