Lambert(兰勃托)投影--我国天气图底图广泛采用的一种投影

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

Lambert.java
001  /**
002 
003     Lambert兰勃特投影
004 
005        PACKAGE: cma.common.projection
006       FILENAME: Lambert.java
007       LANGUAGE: Java2 v1.4
008       ORIGINAL: 最初由成气院向卫国袁东升老师编写,但与Micaps1.0的兰勃特投影不一致,距离标准经度远的地方误差增大。
009    DESCRIPTION: Lambert projection coordinate
010         CREATE: 2003-03-06 00:31:21
011         UPDATE: 2007-07-17 根据 http://mathworld.wolfram.com  提供的公式重新编写
012         AUTHOR: 刘泽军 (BJ0773@gmail.com)
013                 广西气象减灾研究所
014                 Guangxi Institude of Meteorology and Disaster-reducing Research(GIMDR)
015      REFERENCE: http://mathworld.wolfram.com/LambertConformalConicProjection.html
016 
017        COMPILE: javac Coordinate.java Lambert.java
018 
019  ********** 重写后,与Micaps1.0版的“T-兰勃脱投影”完全一致! **********
020 
021        HISTORY:
022           0、lbt.cpp,两位老师的源代码
023           1、CCoordinate.cpp,线性和Lambert投影,主要用于FY-2B卫星云图定位和Micaps交互;
024           2、CRotateCoordinate.cpp,坐标旋转,主要是用于柳州Doppler雷达选址时从扫描的军用地图中定位及读取高程信息);
025           3、CLambert.cpp、CLines.cpp,各投影代码独立为类
026           4、Lambert.java,兰勃托投影改写为JAVA版
027           5、Lambert.java,2007-07-17重新编写
028 
029  **/
030 
031  package  cma.common.projection;
032 
033  import  java.io.*;
034  import  java.awt.*;
035  import  java.awt.geom.*;
036  import  java.util.*;
037  import  java.lang.Math.*;
038  import  java.text.DecimalFormat;
039 
040  import  cma.common.atmos.*;
041 
042  public class  Lambert  extends  Coordinate  {
043 
044       //private   double  fn = 0.715566799999999;
045       private  double   F;
046       private  double   n;
047       private  double   p0;
048 
049       private  void  reset ( //Degree
050               double   standardLon,     double   standardLat,
051               double   positionLon,     double   positionLat,
052               int      positionHori,    int      positionVert,
053               double   zoomIndex ) {
054           type            = Coordinate.LAMBERT;
055           standard        =  new  Point2D.Double ( Math.IEEEremainder ( Math.abs ( standardLon ) 360.0 ) 0.0 ) ;
056           center          =  new  Point2D.Double ( Math.IEEEremainder ( Math.abs ( positionLon ) 360.0 ) , positionLat < - 85.0  ? - 85.0  : positionLat >  85.0  85.0  : positionLat ) ;
057           place           =  new  Point ( positionHori, positionVert ) ;
058           scale           = zoomIndex <=  0.0  1.0  : zoomIndex;
059           scaleOriginal   = scale;
060 
061           double   lat1= Math.toRadians ( 30.0 ) , lat2 = Math.toRadians ( 60.0 ) ; //标准纬度
062           double   lat3= Math.toRadians ( 45.0 + 30.0 / 2.0 ) , lat4 = Math.toRadians ( 45.0 + 60.0 / 2 ) ; //标准纬度
063           double   lat5= Math.toRadians ( 45.0 +center.y/ 2.0 ) ,  lat6 = Math.toRadians ( 45.0 +standard.y/ 2.0 ) ;
064           n   = Math.log ( Math.cos ( lat1 ) /Math.cos ( lat2 )) /Math.log ( Math.tan ( lat4 ) /Math.tan ( lat3 )) ;
065           F   = scale *  484.96  * Math.cos ( lat1 ) *Math.pow ( Math.tan ( lat3 ) ,n ) /n; //484.96为根据Micaps1.0拟合得到的数值
066           p0  = F * Math.pow ( 1.0 /Math.tan ( lat6 ) ,n ) ;
067           double   r   = Math.toRadians ( n* ( center.x-standard.x )) ;
068           double   p   = F * Math.pow ( 1.0 /Math.tan ( lat5 ) ,n ) ;
069           double   x   = p * Math.sin ( r ) ;
070           double   y   = p * Math.cos ( r - p0;
071           offset      =  new  Point (( int )( 0.5  + place.x - x ) ( int )( 0.5  + place.y - y )) ;
072       }
073 
074       public  Lambert () {
075           reset (
076               110.0 ,   30.0 ,
077               110.0 ,   35.0 ,
078               512 ,     384 ,
079               1
080           ) ;
081       }
082 
083       public  Lambert ( //Degree
084               double   standardLon,     double   standardLat,
085               double   positionLon,     double   positionLat,
086               int      positionHori,    int      positionVert,
087               double   zoomIndex ) {
088           reset (
089               standardLon,standardLat,
090               positionLon,    positionLat,
091               positionHori,   positionVert,
092               zoomIndex
093           ) ;
094       }
095 
096       public  Lambert ( //Degree
097               double   positionLon,     double   positionLat,
098               int      positionHori,    int      positionVert,
099               double   zoomIndex ) {
100           reset (
101               110.0 ,       30.0 ,
102               positionLon,    positionLat,
103               positionHori,   positionVert,
104               zoomIndex
105           ) ;
106       }
107 
108  /**
109    * 功能:获得屏幕坐标
110    * 参数:
111    *      lon     - 经度值(度)
112    *      lat     - 纬度值(度)
113    * 返回值:
114    *      屏幕坐标
115    */
116       public  Point getPosition ( double  lon,  double  lat ) {
117           double   lat5= Math.toRadians ( 45.0 +lat/ 2.0 ) ;
118           double   r   = Math.toRadians ( n* ( lon-standard.x )) ;
119           double   p   = F * Math.pow ( 1.0 /Math.tan ( lat5 ) ,n ) ;
120           double   x   = p * Math.sin ( r ) ;
121           double   y   = p * Math.cos ( r - p0;
122           return ( new  Point (( int )( 0.5  + offset.x + x ) ( int )( 0.5  + offset.y + y ))) ;
123       }
124 
125  /**
126    * 功能:获得经纬度坐标
127    * 参数:
128    *  xScreen     - 屏幕坐标值(x方向)
129    *  yScreen     - 屏幕坐标值(y方向)
130    * 返回值:
131    *      经纬度坐标
132    */
133       public  Point2D.Double getCoordinate ( int  x,  int  y ) {
134 
135           double   lon, lat, r;
136           if y-offset.y+p0 ==  ) {
137               lon = standard.x+ 45.0 /n;
138               lat =  2.0 * ( Math.toDegrees ( Math.atan ( 1.0 /Math.pow (( x-offset.x ) /F, 1.0 /n ))) - 45.0 ) ;
139           }
140           else  {
141               lon = standard.x + Math.toDegrees ( Math.atan (( x-offset.x ) / ( y-offset.y+p0 ))) /n;
142               r   = Math.toRadians ( n* ( lon-standard.x )) ;
143               lat =  2.0 * ( Math.toDegrees ( Math.atan ( 1.0 /Math.pow (( y-offset.y+p0 ) /Math.cos ( r ) /F, 1.0 /n ))) - 45.0 ) ;
144           }
145           return ( new  Point2D.Double ( lon,lat )) ;
146       }
147 
148  /**
149    * 功能:获得相对于标准经度的偏角
150    * 参数:
151    *  degreeLon   - 经度值
152    *  degreeLat   - 纬度值
153    * 返回值:
154    *      偏角
155    */
156       public  double  getAngle ( double  degreeLon,  double  degreeLat ) {
157           if 9999.0  <= degreeLat || - 9999.0  >= degreeLat ||  90.0  == degreeLat || - 90.0  == degreeLat  ) {
158               return ( 0.0 ) ;
159           }
160           Point   xy1     = getPosition ( standard.x,  90.0 ) ;
161           Point   xy2     = getPosition ( degreeLon, degreeLat ) ;
162           double   x1      = xy1.x;
163           double   y1      = xy1.y;
164           double   x2      = xy2.x;
165           double   y2      = xy2.y;
166           double   rotateAngle =  0.0 ;
167           if x2 == x1  ) {
168               rotateAngle = y2 >= y1 ?  0.0  180.0 ;
169           }
170           else if y1 == y2  ) {
171               rotateAngle = x2 >= x1 ?  270.0  90.0 ;
172           }
173           else  { //分象限判断旋转角度,坐标原点在xy1
174               double   deltaY      = Math.abs ( y2 - y1 ) ;
175               double   r           = Math.sqrt (( x2 - x1 ) * ( x2 - x1 ( y2 - y1 ) * ( y2 - y1 )) ;
176               double   angelDegree = Math.toDegrees ( Math.asin ( deltaY/r )) ;
177               if x2 > x1 && y2 > y1  ) {
178                   rotateAngle = - 90.0  + angelDegree;
179               }
180               else if x2 > x1 && y2 < y1  ) {
181                   rotateAngle = - 90.0  - angelDegree;
182               }
183               else if x2 < x1 && y2 < y1  ) {
184                   rotateAngle =  90.0  + angelDegree;
185               }
186               else if x2 < x1 && y2 > y1  ) {
187                   rotateAngle =  90.0  - angelDegree;
188               }
189               else  {
190                   return ( Algorithm.DefaultValue ) ;
191               }
192           }
193           return ( rotateAngle ) ;
194       }
195 
196  /**
197    * 功能:
198    *      画经线、纬线
199    * 参数:
200    *      g       - 图形设备
201    *      f       - 字体
202    *      c       - 画线颜色
203    *      inc_lon - 经线间隔
204    *      inc_lat - 纬线间隔
205    * 返回值:
206    *      无
207    */
208       public  void  drawGridLine ( Graphics2D g, Font f, Color c,  int  inc_lon,  int  inc_lat ) {
209 
210           DecimalFormat   df  =  new  DecimalFormat ( "0.#" ) ;
211           Color   saveColor   = g.getColor () ;
212           Font    saveFont    = g.getFont () ;
213           g.setColor ( c ) ;
214           g.setFont ( null ==f?f: new  Font ( "Times New Roman" , Font.PLAIN,  12 )) ;
215           Point       xy, xy1;
216           double       rotateAngle;
217           FontMetrics fm  = g.getFontMetrics () ;
218           String      text;
219           byte         tmpByte [] ;
220           int          bytesWidth, bytesHeight = fm.getHeight () ;;
221           g.setColor ( c ) ;
222           Point   pos1, pos2;
223           //画纬线
224           for ( int  lat= 80 ;lat>=- 80 +inc_lat;lat=lat-inc_lat ) {
225               for ( int  lon= 0 ;lon< 360 ;lon++ ) {
226                   pos1    = getPosition ( lon, lat ) ;
227                   pos2    = getPosition ( lon+ 1 , lat ) ;
228                   g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;
229                   if lon %  90  ==  ) {
230                       g.translate ( pos1.x, pos1.y ) ;
231                       rotateAngle = getAngle ( lon, lat ) ;
232                       if rotateAngle != Algorithm.DefaultValue  ) {
233                           g.rotate ( Math.toRadians ( rotateAngle )) ;   //偏角
234                       }
235                       text        = df.format ( lat ) ;
236                       tmpByte     = text.getBytes () ;
237                       bytesWidth  = fm.bytesWidth ( tmpByte,  0 , tmpByte.length ) ;
238                       g.drawString ( text, -bytesWidth/ 2 , bytesHeight/ 3 ) ; //标纬度值
239                       if rotateAngle != Algorithm.DefaultValue  ) {
240                           g.rotate ( Math.toRadians ( -rotateAngle )) //偏角
241                       }
242                       g.translate ( -pos1.x, -pos1.y ) ;
243                   }
244               }
245           }
246           //画经线
247           for ( int  lon= 0 ;lon<= 360 ;lon=lon+inc_lon ) {
248               pos1    = getPosition ( lon,   80.0 ) ;
249               pos2    = getPosition ( lon, - 80.0 ) ;
250               g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;
251               pos1    = getPosition ( lon,    0.0 ) ;
252               g.translate ( pos1.x, pos1.y ) ;
253               rotateAngle = getAngle ( lon,  0.0 ) ;
254               if rotateAngle != Algorithm.DefaultValue  ) {
255                   g.rotate ( Math.toRadians ( rotateAngle )) ;   //偏角
256               }
257               text        = df.format ( lon ) ;
258               tmpByte     = text.getBytes () ;
259               bytesWidth  = fm.bytesWidth ( tmpByte,  0 , tmpByte.length ) ;
260               g.drawString ( text, -bytesWidth/ 2 , bytesHeight/ 3 ) ; //标纬度值
261               if rotateAngle != Algorithm.DefaultValue  ) {
262                   g.rotate ( Math.toRadians ( -rotateAngle )) //偏角
263               }
264               g.translate ( -pos1.x, -pos1.y ) ;
265           }
266           g.setFont ( saveFont ) ;
267           g.setColor ( saveColor ) ;
268       }
269  }
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值