高斯投影又称横轴椭圆柱等角投影, 假象有一椭圆柱面横套在地球椭球体外面,并与某一条子午线(称中央子午线或轴子午线)相切,椭圆柱的中心轴通过椭球体中心,然后用一定的投影方法将中央子午线两侧各一定经差范围内的地区投影到椭圆柱面上,再将此柱面展开即成为投影面。
为限制投影变形的大小需要分带。我国规定按经差6°和3°进行投影分带,为大比例尺测图和工程测量采用3°带投影。特殊情况下工程测量控制网也可用1.5°带或任意带。高斯投影6°带自0°子午线起每隔经差6°自西向东分带,依次编号1,2,3,…。我国6°中央子午线的经度,由69°起每隔6°而至135° ,共计12带,带号用n表示,中央子午线的经度用L0表示。
在前一章基础中已经讲过,不同的椭球体有对应的椭球基准参数
椭球体基准
public enum Ellipsoid {
/**
* 西安80参心椭球
*/
XIAN_80(80,6378140.0,6356755.28815753,1 / 298.25722101),
/**
* 北京54参心椭球
*/
BEIJING_54(54,6378245.0,6356863.0188,1/298.3),
/**
* WGS84地心椭球
*/
WGS_84(84,6378137.0,6356752.31419,1/298.25722356),
/**
*国家大地2000地心椭球
*/
CGCS_2000(2000,6378137.0,6356752.31414,1/ 298.257222101),;
private int id;
/**
* 椭球长轴,单位米
*/
private double macroAxis;
/**
* 椭球短轴,单位米
*/
private double minorAxis;
/**
* 椭球扁率
*/
private double flattening;
Ellipsoid(int id,double macroAxis, double minorAxis, double flattening) {
this.id = id;
this.macroAxis = macroAxis;
this.minorAxis = minorAxis;
this.flattening = flattening;
}
public static Ellipsoid getSpheroid(int id) {
for (Ellipsoid ellipsoid : Ellipsoid.values()) {
if (ellipsoid.getId() == id) {
return ellipsoid;
}
}
throw new IllegalArgumentException();
}
public double getMacroAxis() {
return macroAxis;
}
public double getMinorAxis() {
return minorAxis;
}
public double getFlattening() {
return flattening;
}
public int getId() {
return id;
}
}
平面坐标
public class GaussCoordinate extends AbstractCoordinate {
/**
* cad图纸x轴,对应西安80图纸 Y 东轴
*/
private double x_L;
/**
* cad图纸y轴,对应西安80图纸 X 北轴
*/
private double y_B;
/**
* 高程
*/
private double z_H;
public GaussCoordinate(String No,double x_L, double y_B, Double z_H, Integer projNo,int projType,int ellipsoid) {
z_H = z_H == null ? 0 : z_H;
projNo = projNo == null ? 0 : projNo;
this.No = No;
this.x_L = x_L;
this.y_B = y_B;
this.z_H = z_H;
this.projNum = projNo;
this.projType = projType;
this.ellipsoid = ellipsoid;
}
public GaussCoordinate standard() {
long X0 = 1000000L * projNum ;
x_L = x_L + X0;
return this;
}
public GaussCoordinate reality() {
int X0 = -500000 ;
x_L = x_L + X0;
return this;
}
public double x_B() {
return x_L;
}
public void setX_L(double x_L) {
this.x_L = x_L;
}
public double y_L() {
return y_B;
}
public void setY_B(double y_B) {
this.y_B = y_B;
}
public double z_H() {
return z_H;
}
public void setZ_H(double z_H) {
this.z_H = z_H;
}
public int projNum() {
return projNum;
}
public void setProjNum(int projNum) {
this.projNum = projNum;
}
public int projType() {
return projType;
}
public void setProjType(int projType) {
this.projType = projType;
}
public int ellipsoid() {
return ellipsoid;
}
public void setEllipsoid(int ellipsoid) {
this.ellipsoid = ellipsoid;
}
@Override
public String toString() {
return "GaussCoordinate{" +
"x_L=" + x_L +
", y_B=" + y_B +
", z_H=" + z_H +
", projNum=" + projNum +
", projType=" + projType +
", ellipsoid=" + ellipsoid +
'}';
}
}
大地经纬度坐标
public class BLHCoordinate extends AbstractCoordinate {
/**
* 经度
*/
private double L_longitude;
/**
* 维度
*/
private double B_latitude;
/**
* 高程
*/
private double H_height;
/**
* 商业地图类型
*/
private int mapType
public BLHCoordinate(String No,double longitude, double latitude, double height,int projType,int ellipsoid) {
this.No = No;
this.L_longitude = longitude;
this.B_latitude = latitude;
this.H_height = height;
this.projType = projType;
this.ellipsoid = ellipsoid;
this.projNum= GisUtil.countProjNumber(this.L_longitude,this.projType);
}
public double L_longitude() {
return L_longitude;
}
public void setL_longitude(double l_longitude) {
L_longitude = l_longitude;
}
public double B_latitude() {
return B_latitude;
}
public void setB_latitude(double b_latitude) {
B_latitude = b_latitude;
}
public double H_height() {
return H_height;
}
public void setH_height(double h_height) {
H_height = h_height;
}
public int projType() {
return projType;
}
public void setProjType(int projType) {
this.projType = projType;
}
public int ellipsoid() {
return ellipsoid;
}
public void setEllipsoid(int ellipsoid) {
this.ellipsoid = ellipsoid;
}
public int mapType() {
return mapType;
}
public void setMapType(int mapType) {
this.mapType = mapType;
}
public int projNum() {
return this.projNum;
}
public void setProjNum(int projNum) {
this.projNum = projNum;
}
@Override
public String toString() {
return "BLHCoordinate{" +
"L_longitude=" + L_longitude +
", B_latitude=" + B_latitude +
", H_height=" + H_height +
", mapType=" + mapType +
", No='" + No +
", projNum=" + projNum +
", projType=" + projType +
", ellipsoid=" + ellipsoid +
'}';
}
}
大地经纬度转高斯平面
/**
* 由经纬度反算成高斯一般投影坐标
* 不带带号
*
* @param ellipsoid 椭球体 对应坐标体系
* @return
*/
public static GaussCoordinate BLToGaussNormal(BLHCoordinate coordinate,Ellipsoid ellipsoid) {
int projNo = 0; //带号
int ZoneWide; //带宽
double longitude1, latitude1, longitude0, latitude0, X0, Y0, xval, yval;
double a, f, e2, ee, NN, T, C, A, M, iPI;
double longitude = coordinate.L_longitude();
double latitude = coordinate.B_latitude();
iPI = 0.0174532925199433; //3.1415926535898/180.0;
a = ellipsoid.getMacroAxis();//长轴
f = ellipsoid.getFlattening(); //扁率
ZoneWide =coordinate.projType(); //带宽
if (ZoneWide == THREE_DEGREE) {
Double temp = longitude / ZoneWide;
BigDecimal bd = new BigDecimal(temp).setScale(0, BigDecimal.ROUND_HALF_UP);
projNo = bd.intValue();
longitude0 = projNo * ZoneWide;
} else {
projNo = (int) (longitude / ZoneWide + 1);
longitude0 = projNo * ZoneWide - ZoneWide / 2;//中央经度
}
longitude0 = longitude0 * iPI;//中央经度转换为弧度
longitude1 = longitude * iPI; //经度转换为弧度
latitude1 = latitude * iPI; //纬度转换为弧度
e2 = 2 * f - f * f;
ee = e2 * (1.0 - e2);
NN = a / Math.sqrt(1.0 - e2 * Math.sin(latitude1) * Math.sin(latitude1));
T = Math.tan(latitude1) * Math.tan(latitude1);
C = ee * Math.cos(latitude1) * Math.cos(latitude1);
A = (longitude1 - longitude0) * Math.cos(latitude1);
M = a * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256) * latitude1 - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2
* e2 / 1024) * Math.sin(2 * latitude1)
+ (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024) * Math.sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072) * Math.sin(6 * latitude1));
xval = NN * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * ee) * A * A * A * A * A / 120);
yval = M + NN * Math.tan(latitude1) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24
+ (61 - 58 * T + T * T + 600 * C - 330 * ee) * A * A * A * A * A * A / 720);
X0 = 500000L;
xval = xval + X0;
return new GaussCoordinate(coordinate.getNo(),xval, yval, coordinate.H_height(),projNo, ZoneWide,coordinate.ellipsoid());
}
高斯平面转大地经纬度坐标
/**
* 由高斯通用标准投影坐标反算成经纬度
*
* @param ellipsoid 椭球体 对应坐标体系
* @return
*/
public static BLHCoordinate GaussToBL(GaussCoordinate coordinate, Ellipsoid ellipsoid) {
double X=coordinate.x_B(), Y=coordinate.y_L();
int projType = coordinate.projType();
int ProjNo;
int ZoneWide; //带宽
double longitude1, latitude1, longitude0, X0, Y0, xval, yval;//latitude0,
double e1, e2, f, a, ee, NN, T, C, M, D, R, u, fai, iPI;
iPI = 0.0174532925199433; //3.1415926535898/180.0;
a = ellipsoid.getMacroAxis();//长轴
f = ellipsoid.getFlattening(); //扁率
ProjNo = (int) (X / 1000000L); //查找带号
ZoneWide = projType;
if (ZoneWide == THREE_DEGREE) {//3度带
longitude0 = ProjNo * ZoneWide;
} else {//默认6度带计算
longitude0 = ProjNo * ZoneWide - ZoneWide / 2;
}
longitude0 = longitude0 * iPI; //中央经线度转弧度
X0 = ProjNo * 1000000L + 500000L;//带号+500公里
Y0 = 0;
xval = X - X0;
yval = Y - Y0; //带内大地坐标
e2 = 2 * f - f * f;
e1 = (1.0 - Math.sqrt(1 - e2)) / (1.0 + Math.sqrt(1 - e2));
ee = e2 / (1 - e2);
M = yval;
u = M / (a * (1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256));
fai = u + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * u) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(
4 * u)
+ (151 * e1 * e1 * e1 / 96) * Math.sin(6 * u) + (1097 * e1 * e1 * e1 * e1 / 512) * Math.sin(8 * u);
C = ee * Math.cos(fai) * Math.cos(fai);
T = Math.tan(fai) * Math.tan(fai);
NN = a / Math.sqrt(1.0 - e2 * Math.sin(fai) * Math.sin(fai));
R = a * (1 - e2) / Math.sqrt((1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin
(fai) * Math.sin(fai)));
D = xval / NN;
//计算经度(Longitude) 纬度(Latitude) 弧度
longitude1 = longitude0 + (D - (1 + 2 * T + C) * D * D * D / 6 + (5 - 2 * C + 28 * T - 3 * C * C + 8 * ee + 24 * T * T) * D
* D * D * D * D / 120) / Math.cos(fai);
latitude1 = fai - (NN * Math.tan(fai) / R) * (D * D / 2 - (5 + 3 * T + 10 * C - 4 * C * C - 9 * ee) * D * D * D * D / 24
+ (61 + 90 * T + 298 * C + 45 * T * T - 256 * ee - 3 * C * C) * D * D * D * D * D * D / 720);
//转换为度 DD
double longitude = longitude1 / iPI;
double latitude = latitude1 / iPI;
return new BLHCoordinate(coordinate.getNo(),longitude, latitude,coordinate.z_H(), ZoneWide,ellipsoid.getId());
}