Mercator(麦卡托)等角圆柱投影--多用于赤道和低纬地区
何博涛
2023-12-01
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
}