Mercator.java
001 /*
002
003 Mercator 麦卡脱投影
004
005 PACKAGE: cma.common.projection
006 FILENAME: Mercator.java
007 LANGUAGE: Java2 v1.4
008 ORIGINAL: none
009 DESCRIPTION:
010 CREATE: 2007-07-08 13:22:39
011 UPDATE: 2007-07-18
012 AUTHOR: 刘泽军 (BJ0773@gmail.com)
013 广西气象减灾研究所
014 Guangxi Institude of Meteorology and Disaster-reducing Research(GIMDR)
015 REFERENCE: http://mathworld.wolfram.com/MercatorProjection.html
016
017 Compile: javac Coordinate.java Mercator.java
018 */
019
020 package cma.common.projection;
021
022 import java.io.*;
023 import java.awt.*;
024 import java.awt.geom.*;
025 import java.util.*;
026 import java.lang.Math.*;
027 import java.text.DecimalFormat;
028
029 public class Mercator extends Coordinate {
030
031 /**
032 * 功能:
033 * 重置参数
034 * 参数:
035 * lon,lat - 中心经纬度,
036 * px,py - 中心经纬度对应的屏幕坐标
037 * sx,sy - 缩放系数
038 * 返回值:
039 * 无
040 */
041 public void reset ( double lon, double lat, int px, int py, double sc ) {
042 type = Coordinate.MERCATOR;
043 center = new Point2D.Double (
044 lon < 0.0 ? 0.0 : lon > 360.0 ? 360.0 : lon,
045 lat <=- 90.0 ? 0.0 : lat >= 90.0 ? 0.0 : lat
046 ) ;
047 place = new Point ( px, py ) ;
048 scaleXY = new Point2D.Double ( 7.25 , 433.0 ) ; //与Micaps1.0版匹配的参数
049 scale = sc == 0.0 ? 1.0 : Math.abs ( sc ) ;;
050 scaleOriginal = scale;
051 offset = new Point ( 0 , 0 ) ; //未用
052 }
053
054 /**
055 * 功能:
056 * 构造函数
057 * 参数:
058 * 无(使用缺省值)
059 * 返回值:
060 * 无
061 */
062 public Mercator () {
063 reset ( 109.40 , 24.35 , 640 , 480 , 1.0 ) ;
064 }
065
066 /**
067 * 功能:
068 * 构造函数
069 * 参数:
070 * lon,lat - 中心经纬度,
071 * px,py - 中心经纬度对应的屏幕坐标
072 * sc - 缩放系数
073 * 返回值:
074 * 无
075 */
076 public Mercator ( double lon, double lat, int px, int py, double sc ) {
077 reset ( lon, lat, px, py, sc ) ;
078 }
079
080 /**
081 * 功能:
082 * 获得屏幕坐标
083 * 参数:
084 * lon - 经度
085 * lat - 纬度
086 * 返回值:
087 * 屏幕坐标
088 */
089 public Point getPosition ( double lon, double lat ) {
090 if ( lat >= 90.0 || lat <= - 90.0 ) {
091 return ( null ) ;
092 }
093 double x = scale*scaleXY.x* ( lon-center.x ) + place.x;
094 double y1 = Math.log ( Math.tan ( Math.toRadians ( center.y )) + 1.0 /Math.cos ( Math.toRadians ( center.y ))) ;
095 double y2 = Math.log ( Math.tan ( Math.toRadians ( lat )) + 1.0 /Math.cos ( Math.toRadians ( lat ))) ;
096 double y = scale*scaleXY.y * ( y1-y2 ) + place.y;
097 return (
098 new Point (
099 ( int )( x+ 0.5 ) ,
100 ( int )( y+ 0.5 )
101 )
102 ) ;
103 }
104
105 /**未完成
106 * 功能:
107 * 获得屏幕坐标对应的经纬度
108 * 参数:
109 * x - 屏幕水平坐标
110 * y - 屏幕垂直坐标
111 * 返回值:
112 * 对应的经纬度
113 */
114 public Point2D.Double getCoordinate ( int x, int y ) {
115 double y1 = Math.log ( Math.tan ( Math.toRadians ( center.y )) + 1.0 /Math.cos ( Math.toRadians ( center.y ))) ;
116 double y2 = y1 - ( y - place.y ) / scale / scaleXY.y;
117 /*
118 double y2 = Math.log(Math.tan(Math.toRadians(lat))+1.0/Math.cos(Math.toRadians(lat)));
119 exp(y2)=tan(lat)+1.0/cos(lat)
120 exp(y2)=(sin(lat)+1)/sqrt(1-sin(lat)*sin(lat))
121 1-sin(lat)*sin(lat)=(1+sin(lat))*(1+sin(lat))/(exp(y2)*exp(y2))
122 (1-sin(lat))=(1+sin(lat))/(exp(y2)*exp(y2))
123 1.0/(exp(y2)*exp(y2))+sin(lat)/(exp(y2)*exp(y2))+sin(lat)-1=0;
124 sin(lat)*(1.0+1.0/(exp(y2)*exp(y2)))=1.0-1.0/(exp(y2)*exp(y2))
125 sin(lat)*(exp(y2)*exp(y2)+1)=(exp(y2)*exp(y2)-1)
126 sin(lat)=(exp(y2)*exp(y2)-1)/(exp(y2)*exp(y2)+1)
127
128 */
129 double lon = ( x - place.x ) / scale/scaleXY.x + center.x;
130 double lat = Math.toDegrees ( Math.asin (( Math.exp ( y2 ) *Math.exp ( y2 ) - 1 ) / ( Math.exp ( y2 ) *Math.exp ( y2 ) + 1 ))) ;
131 return (
132 new Point2D.Double (
133 lon,
134 lat
135 )
136 ) ;
137 }
138
139 /**
140 * 功能:
141 * 画经线、纬线
142 * 参数:
143 * g - 图形设备
144 * f - 字体
145 * c - 画线颜色
146 * inc_lon - 经线间隔
147 * inc_lat - 纬线间隔
148 * 返回值:
149 * 无
150 */
151 public void drawGridLine ( Graphics2D g, Font f, Color c, int inc_lon, int inc_lat ) {
152
153 DecimalFormat df = new DecimalFormat ( "0.#" ) ;
154 Color saveColor = g.getColor () ;
155 Font saveFont = g.getFont () ;
156 g.setColor ( c ) ;
157 g.setFont ( null ==f?f: new Font ( "Times New Roman" , Font.PLAIN, 12 )) ;
158 FontMetrics fm = g.getFontMetrics () ;
159 String text;
160 byte tmpByte [] ;
161 int bytesWidth, bytesHeight = fm.getHeight () ;;
162 Point pos1, pos2;
163 if ( inc_lon > 0 ) {
164 for ( double lon= 0.0 ;lon<= 360.0 ;lon=lon+inc_lon ) {
165 if ( 180.0 == lon ) {
166 for ( double lat=- 90.0 +inc_lat;lat<= 90.0 -inc_lat;lat=lat+inc_lat ) {
167 text = df.format ( lat ) ;
168 tmpByte = text.getBytes () ;
169 bytesWidth = fm.bytesWidth ( tmpByte, 0 , tmpByte.length ) ;
170 pos1 = this .getPosition ( lon, lat ) ;
171 g.drawString ( text, pos1.x-bytesWidth/ 2 , pos1.y+bytesHeight/ 3 ) ;
172 }
173 }
174 pos1 = this .getPosition ( lon, - 90.0 +inc_lat ) ;
175 pos2 = this .getPosition ( lon, 90.0 -inc_lat ) ;
176 g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;
177 }
178 }
179 if ( inc_lat > 0 ) {
180 for ( double lat=- 90.0 +inc_lat;lat<= 90.0 -inc_lat;lat=lat+inc_lat ) {
181 if ( 0.0 == lat ) {
182 for ( double lon= 0.0 ;lon<= 360.0 ;lon=lon+inc_lon ) {
183 text = df.format ( lon ) ;
184 tmpByte = text.getBytes () ;
185 bytesWidth = fm.bytesWidth ( tmpByte, 0 , tmpByte.length ) ;
186 pos1 = this .getPosition ( lon, lat ) ;
187 g.drawString ( text, pos1.x-bytesWidth/ 2 , pos1.y+bytesHeight/ 3 ) ;
188 }
189 }
190 pos1 = this .getPosition ( 0.0 , lat ) ;
191 pos2 = this .getPosition ( 360.0 , lat ) ;
192 g.drawLine ( pos1.x, pos1.y, pos2.x, pos2.y ) ;
193 }
194 }
195 g.setFont ( saveFont ) ;
196 g.setColor ( saveColor ) ;
197 }
198 }