Polar.java
001/*
002
003Polar投影(扫描方式,自正北方向顺时针)
004
005PACKAGE:mon.projection
006FILENAME:Polar.java
007LANGUAGE:Java2v1.4
008ORIGINAL:无
009DESCRIPTION:极坐标投影(主要用于雷达图像处理)
010RELATED:mon.projection.Lambert(兰勃特投影)
011EDITOR:UltraEdit-32v12.20a(Windows)NEdit(Linux)
012CREATE:-05-0620:08:23
013UPDATE:-07-18修改为抽象类Coordinate的扩展类
014AUTHOR:刘泽军(BJ0773@)
015广西气象减灾研究所
016GuangxiInstitudeofMeteorologyandDisaster-reducingResearch(GIMDR)
017
018Compile:javacCoordinate.javaPolar.java
019
020HowtousePolarclass:
021
022Polarpolar=newPolar(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*3590
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
072packagemon.projection;
073
074importjava.awt.*;
075importjava.awt.geom.*;
076importjava.lang.Math.*;
077
078publicclassPolarextendsCoordinate{
079
080//私有成员
081privatedoubleperKilometer=1.0;//比例尺:一公里对应的像素点数(扫描平面)
082privatedoubleelevation=0.0;//仰角
083privatedoublecosineElevation=1.0;//仰角的余弦值
084privatedoublekmPerDegreeX=1.0;//1经度对应的距离(公里),不同纬度数值不同
085privatedoublekmPerDegreeY=1.0;//1纬度对应的距离(公里),不同纬度数值不同
086
087/**
088*功能:计算球面上两点间的距离(单位:公里),原在edu.gimdr.Atmos.Meteorology类中写有,为避免import过多的类,故重写一份
089*参数:
090*lon1,lat1-第1点的位置(经纬度)
091*lon2,lat2-第2点的位置(经纬度)
092*返回值:
093*球面距离
094*/
095publicstaticdoubledistanceOfSphere(doublelon1,doublelat1,doublelon2,doublelat2){
096/*公式:
097A(x,y)B(a,b)
098AB点的球面距离=R*{arccos[cos(b)*cos(y)*cos(a-x)+sin(b)*sin(y)]},byGoogle
099*/
100
101doublerlon1=Math.toRadians(lon1);
102doublerlat1=Math.toRadians(lat1);
103doublerlon2=Math.toRadians(lon2);
104doublerlat2=Math.toRadians(lat2);
105
106return(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*/
120publicvoidreset(doublelon,doublelat,intpx,intpy,doublesc,doubleagl){
121type=Coordinate.POLAR;
122center=newPoint2D.Double(
123lon<0.0?0.0:lon>360.0?360.0:lon,
124lat<-90.0?-90.0:lat>90.0?90.0:lat
125);
126place=newPoint(px,py);
127elevation=Math.toRadians(Math.IEEEremainder(Math.abs(agl),90.0));//在0-90度之间,但不能为90度
128cosineElevation=Math.cos(elevation);//仰角的余弦值
129scale=sc==0.0?1.0:Math.abs(sc);//缩放系数
130scaleOriginal=scale;
131offset=newPoint(0,0);
132
133perKilometer=1.0;//标准比例尺
134//中心经纬度或仰角发生改变,必须重新计算经向和纬向的1度对应的球面距离
135kmPerDegreeX=distanceOfSphere(center.x,center.y,center.x+1.0,center.y)/cosineElevation;
136kmPerDegreeY=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*/
150publicPolar(doublelon,doublelat,intx,inty,doublesc){
151reset(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*/
166publicPolar(doublelon,doublelat,intx,inty,doublesc,doubleagl){
167reset(lon,lat,x,y,sc,agl);
168}
169
170/**
171*功能:获得仰角
172*参数:
173*无
174*返回值:
175*仰角的度数
176*/
177publicdoublegetElevation(){
178return(Math.toDegrees(elevation));
179}
180
181/**
182*功能:获得经纬度对应的屏幕像素坐标,与雷达仰角有关,主要用于体扫数据显示、底图叠加等。
183*参数:
184*lon-经度
185*lat-纬度
186*返回值:
187*对应的屏幕坐标
188*/
189publicPointgetPosition(doublelon,doublelat){
190doubledisX=distanceOfSphere(lon,center.y,center.x,center.y)/cosineElevation;
191doubledisY=distanceOfSphere(center.x,lat,center.x,center.y)/cosineElevation;
192doublex=(lon>center.x?1:-1)*(disX*perKilometer*scale)+place.x+0.5;
193doubley=-(lat>center.y?1:-1)*(disY*perKilometer*scale)+place.y+0.5;
194return(newPoint((int)x,(int)y));
195}
196
197/**
198*功能:获得极坐标对应的屏幕像素坐标,与雷达仰角无关,主要用于体扫数据显示、底图叠加等。
199*参数:
200*radius-极半径
201*angle-角度(以正北方向顺时针)
202*返回值:
203*对应的屏幕坐标
204*/
205
206publicPointgetXY(doubleradius,doubleangle){
207intx=(int)(0.5+radius*Math.sin(Math.toRadians(angle)));
208inty=(int)(0.5+radius*Math.cos(Math.toRadians(angle)));
209return(newPoint(place.x+x,place.y-y));
210}
211
212/**
213*功能:获得屏幕像素点位置的极坐标半径,由于是输入参数是扫描平面上的值,故与雷达仰角无关。
214*参数:
215*x-水平坐标
216*y-垂直坐标
217*返回值:
218*与极坐标中心的距离,即极半径
219*/
220publicdoublegetRadius(intx,inty){
221return(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*/
232publicdoublegetRadius(doublelon,doublelat){
233Pointpos=getPosition(lon,lat);//此函数已经考虑了仰角的影响
234return(getRadius(pos.x,pos.y));
235}
236
237/**
238*功能:获得屏幕像素点位置的极坐标角度(扫描平面与0度平面均相同),与雷达仰角无关。
239*参数:
240*x-水平坐标
241*y-垂直坐标
242*返回值:
243*角度值,自正北方向顺时针
244*/
245publicdoublegetAngle(intx,inty){
246doubleagl=0.0;
247if(x==place.x&&y==place.y){//重合
248agl=0.0;
249}
250elseif(x==place.x){
251agl=y>place.y?180.0:360.0;
252}
253elseif(y==place.y){
254agl=x>place.x?90.0:270.0;
255}
256else{
257agl=Math.toDegrees(Math.atan(1.0*Math.abs(x-place.x)/Math.abs(y-place.y)));
258agl=
259x>place.x&&y<place.y?agl://直角坐标的第一象限
260x<place.x&&y<place.y?180.0-agl://直角坐标的第二象限
261x<place.x&&y>place.y?180.0+agl://直角坐标的第三象限
262x>place.x&&y>place.y?360.0-agl://直角坐标的第四象限
263agl;
264}
265System.out.println(agl);
266return(agl);
267}
268
269/**
270*功能:获得经纬度位置的极坐标角度(扫描平面与0度平面均相同),与雷达仰角无关。
271*参数:
272*lon-水平坐标
273*lat-垂直坐标
274*返回值:
275*角度值,自正北方向顺时针
276*/
277publicdoublegetAngle(doublelon,doublelat){
278/*
279//若通过获得屏幕坐标来计算角度,精度比较差,特别是在极坐标中心附近
280Pointp=getPosition(lon,lat);
281return(getAngle(p.x,p.y);
282*/
283doubleagl=0.0;
284if(lon==center.x&&lat==center.y){//重合
285agl=0.0;
286}
287elseif(lon==center.x){
288agl=lat>center.y?360.0:180.0;
289}
290elseif(lat==center.y){
291agl=lon>center.x?90.0:270.0;
292}
293else{
294//注:由于经向和纬向的球面距离不等(华南,经向>纬向),故点(1,1)与中心点(0,0)的极角不等45度,而应是略大于45度
295agl=Math.toDegrees(Math.atan((Math.abs(lon-center.x)*kmPerDegreeX)/(Math.abs(lat-center.y)*kmPerDegreeY)));
296agl=
297lon>center.x&&lat>center.y?agl://第一象限
298lon<center.x&&lat>center.y?180.0-agl://第二象限
299lon<center.x&&lat<center.y?180.0+agl://第三象限
300lon>center.x&&lat<center.y?360.0-agl://第四象限
301agl;
302}
303return(agl);
304}
305
306/**
307*功能:
308*获得屏幕坐标对应的经纬度
309*参数:
310*x-屏幕水平坐标
311*y-屏幕垂直坐标
312*返回值:
313*对应的经纬度
314*/
315publicPoint2D.DoublegetCoordinate(intx,inty){
316doublelat=Math.toDegrees(Math.toRadians(center.y)+(place.y-y)*cosineElevation/perKilometer/scale/Polar.RADIUS);
317doubledisX0=distanceOfSphere(center.x,lat,center.x+1.0,lat);//0度平面上1经度的球面距离
318doubledisX=disX0/cosineElevation;//扫描平面上1经度的距离
319doubleperDegreeX=disX*perKilometer*scale;//扫描平面上1经度的对应的像素点数
320doublelon=center.x+(x-place.x)/perDegreeX;
321return(newPoint2D.Double(lon,lat));
322}
323
324/**
325*功能:
326*画经线、纬线
327*参数:
328*g-图形设备
329*f-字体
330*c-画线颜色
331*inc_lon-经线间隔//未使用
332*inc_lat-纬线间隔//未使用
333*返回值:
334*无
335*/
336publicvoiddrawGridLine(Graphics2Dg,Fontf,Colorc,intinc_lon,intinc_lat){
337ColorsaveColor=g.getColor();
338FontsaveFont=g.getFont();
339
340//以下两行改进线条的锯齿
341//RenderingHintsrenderHints=newRenderingHints(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
347g.setColor(c);//雷达图形区域的边框颜色
348g.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//画极径
351Pointpos1,pos2;
352for(doublei=0.0;i<180.0;i=i+30.0){
353pos1=getXY(scale*240.0,0.0+i);
354pos2=getXY(scale*240.0,180.0+i);
355g.drawLine(pos1.x,pos1.y,pos2.x,pos2.y);
356}
357
358//画极圈
359for(inti=50;i<=200;i=i+50){//每50公里画一个圈
360g.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}
362g.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
364g.setFont(saveFont);
365g.setColor(saveColor);
366}
367}