三参数法和七参数法均应用于空间直角坐标系的转换。
三参数坐标转换公式在假设两坐标系间各坐标轴相互平行,轴系间不存在欧勒角的条件下得出的。
【七参数】法:
如上图:两个空间直角坐标系分别为O1-X1Y1Z1与O2-X2Y2Z2,它们的原点不一致,相应的坐标轴相互不平行,两个坐标轴间除了三个平移参数,还有三个欧勒角,即三个旋转参数,又考虑到两个坐标系的尺度不尽一,还需设一个尺度变化参数m,总计共有七个参数。
用七参数进行空间直角坐标系转换有布尔莎公式、莫洛琴斯基公式和范式公式等。下面给出布尔莎七参数公式:
写成一般形式为:
七参数公式比较三参数公式能获得较高精度的转换结果。实际应用中,也可以舍弃不显著的参数,例如个别欧勒角,选择四、五或六个参数进行不同空间直角坐标系统的转换。
https://zhidao.baidu.com/question/1045966105464699179.html
了解坐标系
在大地测量学中,坐标系分为两大类:地心坐标系和参心坐标系。地心坐标系是坐标系原点与地球质心重合的坐标系,参心坐标系是坐标系原点位于参考椭球体中心,但不与地球质心重合的坐标系。我国使用的1954北京坐标系,1980西安坐标系都属于参心坐标系。GPS中使用的世界大地坐标系WGS-84属于地心坐标系,我国最近开始启用的中国大地坐标系2000(即CGCS2000),也属于地心坐标系。以上两大类坐标系都有下列几种表达形式:1.空间大地坐标系,即大地经纬度(B,L,H)形式2.空间直角坐标系,即三维空间坐标(X,Y,Z)形式3.投影平面直角坐标系。即二维平面坐标(x,y,h)形式 在工程测量和施工中,我国普遍使用的是1954北京或1980西安的高斯投影平面直角坐标系。 但为满足工程施工精度要求,通常会在测区建立独立的地方坐标系,且独立地方坐标系都能够通过转换公式换算为国家统一的坐标系上,如1954北京坐标系或1980西安坐标系
1,大地坐标(BLH)对平面直角坐标(XYZ)
常规的转换应先确定转换参数,即椭球参数、分带标准(3度,6度)和中央子午线的经度。椭球参数就是指平面直角坐标系采用什么样的椭球基准,对应有不同的长短轴及扁率。一般的工程中3度带应用较为广泛。对于中央子午线的确定有两种方法,一是取平面直角坐标系中Y坐标的前两位*3,即可得到对应的中央子午线的经度。如x=3250212m,y=395121123m,则中央子午线的经度=39*3=117度。另一种方法是根据大地坐标经度,如果经度是在155.5~185.5度之间,那么对应的中央子午线的经度=(155.5+185.5)/2=117度,其他情况可以据此3度类推。
另外一些工程采用自身特殊的分带标准,则对应的参数确定不在上述之列。
确定参数之后,可以用软件进行转换,以下提供坐标转换的程序下载。
2,北京54全国80及WGS84坐标系的相互转换
这三个坐标系统是当前国内较为常用的,它们均采用不同的椭球基准。
其中北京54坐标系,属三心坐标系,大地原点在苏联的普而科沃,长轴6378245m,短轴6356863,扁率1/298.3;西安80坐标系,属三心坐标系,大地原点在陕西省径阳县永乐镇,长轴6378140m,短轴6356755,扁率1/298.25722101;WGS84坐标系,长轴6378137.000m,短轴6356752.314,扁率1/298.257223563。由于采用的椭球基准不一样,并且由于投影的局限性,使的全国各地并不存在一至的转换参数。对于这种转换由于量较大,有条件的话,一般都采用GPS联测已知点,应用GPS软件自动完成坐标的转换。当然若条件不许可,且有足够的重合点,也可以进行人工解算。详细方法见第三类。
3.任意两空间坐标系的转换
由于测量坐标系和施工坐标系采用不同的标准,要进行精确转换,必须知道至少3个重合点(即为在两坐标系中坐标均为已知的点。采用布尔莎模型进行求解。布尔莎公式:
对该公式进行变换等价得到:
解算这七个参数,至少要用到三个已知点(2个坐标系统的坐标都知道),采用间接平差模型进行解算:
其中: V 为残差矩阵;
X 为未知七参数;
A 为系数矩阵;
解之:L 为闭合差
解得七参数后,利用布尔莎公式就可以进行未知点的坐标转换了,每输入一组坐标值,就能求出它在新坐标系中的坐标。 但是要想GPS观测成果用于工程或者测绘,还需要将地方直角坐标转换为大地坐标,最后还要转换为平面高斯坐标。
上述方法类同于我们的间接平差,解算起来较复杂,以下提供坐标转换程序,只需输入三个已知点的坐标即可求解出坐标转换的七个参数。如果已知点的数量较多,可以进行参数间的平差运算,则精度更高。
当已知点的数量只有两个时,我们可以采用简单变换法,此法较为方便易行,适于手算,只是精度受到一定的限制。
详细解算方程如下:
式中调x,y和x\'、y\'分别为新旧(或;旧新)网重合点的坐标,a、b、、k为变换参数,显然要解算出a、b、、k,必须至少有两个重合点,列出四个方程。
即可进行通常的参数平差,解求a、x、b、c、d各参数值。将之代人(3)式,可得各拟合点的残差(改正数)代人(2)式,可得待换点的坐标。
求出解算参数之后,可输入源坐标进行目标坐标的转换。
http://blog.163.com/zhzh_212/blog/static/505580332008111142523910/
课外了解
http://blog.csdn.net/findsafety/article/details/12442639
以上参考自:haotsp.com
总结:
WGS84坐标系:即地球坐标系,国际上通用的坐标系。
GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。
BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。
搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。
API | 坐标系 |
百度地图API | 百度坐标 |
腾讯搜搜地图API | 火星坐标 |
搜狐搜狗地图API | 搜狗坐标* |
阿里云地图API | 火星坐标 |
图吧MapBar地图API | 图吧坐标 |
高德MapABC地图API | 火星坐标 |
灵图51ditu地图API | 火星坐标 |
注1:百度地图使用百度坐标,支持从地球坐标和火星坐标导入成百度坐标,但无法导出。并且批量坐标转换一次只能转换20个(待验证)。
注2:搜狗地图支持直接显示地球坐标,支持地球坐标、火星坐标、百度坐标导入成搜狗坐标,同样,搜狗坐标也无法导出。
个人认为:采用自家坐标体系,而不采用国内通用的火星坐标体系,实在是自寻短处。当然,百度是因为做的足够大、足够好,所以很霸道,也为以后一统天下而不让别人瓜分之而做准备吧。搜狗虽然用自家坐标体系,但能将地球坐标直接导入,此举也属唯一。而图吧地图不知道学什么加密方式,以前用地球坐标用的好好的,现在用图吧自己的坐标,难道是因为给百度做过所以也来了这么一招?或者沿用百度?不得而知。
本文的目的在于:做地图开发的时候,不希望被一家地图API迁就,所以采用火星坐标是正确的选择,希望本文能够对选择使用谁家API的开发者提供一点帮助吧。就我个人而言,我绝不会使用非火星坐标系统的地图API,虽然百度地图API很好很强大确实很吸引我。公司用的天地图o(*^@^*)o
Java代码
package com.test.bao;
import java.util.Scanner;
/**
* 进行7参坐标转换
* 注意只有该类用于七参数计算
* 其他类用于其他操作,下载者可以不予理会。
*
* @author wyd
*
*/
public class SevenParamsTest {
/**
* @列主元高斯消去法 注意所有数组索引坐标均从1开始
*/
static double a[][];
static double b[];
static double x[];
static int n;
static int n2; // 记录换行的次数
public static void Elimination() { // 消元
for (int k = 1; k <= n - 1; k++) {
Wrap(k);
for (int i = k + 1; i <= n; i++) {
double l = a[i][k] / a[k][k];
a[i][k] = 0.0;
for (int j = k + 1; j <= n; j++)
a[i][j] = a[i][j] - l * a[k][j];
b[i] = b[i] - l * b[k];
}
System.out.println("第" + k + "次消元后:");
PrintA();
}
}
public static void Back()// 回代
{
x[n] = b[n] / a[n][n];
for (int i = n - 1; i >= 1; i--)
x[i] = (b[i] - jisuan(i)) / a[i][i];
}
public static double jisuan(int i) {
double he = 0.0;
for (int j = i + 1; j <= n; j++)
he = he + x[j] * a[i][j];
return he;
}
public static void Wrap(int k) {// 换行
double max = Math.abs(a[k][k]);
int n1 = k; // 记住要交换的行
for (int i = k + 1; i <= n; i++) // 找到要交换的行
{
if (Math.abs(a[i][k]) > max) {
n1 = i;
max = Math.abs(a[i][k]);
}
}
if (n1 != k) {
n2++;
System.out.println("当k=" + k + "时,要交换的行是:" + k + "和" + n1);
for (int j = k; j <= n; j++) // 交换a的行
{
double x1;
x1 = a[k][j];
a[k][j] = a[n1][j];
a[n1][j] = x1;
}
double b1; // 交换b的行
b1 = b[k];
b[k] = b[n1];
b[n1] = b1;
System.out.println("交换后:");
PrintA();
}
}
public static void Determinant() {// 求行列式
double DM = 1.0;
for (int i = 1; i <= n; i++) {
double a2 = a[i][i];
DM = DM * a2;
}
double n3 = (double) n2;
DM = DM * Math.pow(-1.0, n3);
System.out.println("该方程组的系数行列式:det A = " + DM);
}
public static void PrintA() {// 输出增广矩阵
System.out.println("增广矩阵为:");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
System.out.print(a[i][j] + " ");
System.out.print(b[i] + " ");
System.out.print("\n");
}
}
public static void Print() {// 输出方程的根
System.out.println("方程组的根为:");
for (int i = 1; i <= n; i++)
System.out.println("x" + i + " = " + x[i]);
}
public static void main(String[] args) {
Scanner as = new Scanner(System.in);
int sum;
System.out.println("输入计算7参时用到的坐标对数:");
sum = as.nextInt();
// System.out.println("输入方程组的元数:");
// n = as.nextInt();6
// 三个源坐标保存数组
double[] srcCoordinate = new double[sum * 3];
// 三个目标坐标数组
double[] destCoordinate = new double[sum * 3];
n = 7;
a = new double[n + 1][n + 1];
b = new double[n + 1];
x = new double[n + 1];
// System.out.println("输入方程组的系数矩阵a:");
System.out.println("按顺序输入" + sum + "个源坐标:");
for (int i = 0; i < srcCoordinate.length; i++) {
srcCoordinate[i] = as.nextDouble();
}
System.out.println("按顺序输入" + sum + "个目标坐标:");
for (int i = 0; i < destCoordinate.length; i++) {
destCoordinate[i] = as.nextDouble();
}
// 将源坐标存储到二维数组中
int index = 0;// 记录当前循环索引
double[][] srcTemporary = new double[sum][3];
for (int i = 0; i < sum; i++) {
for (int j = 0; j < 3; j++) {
srcTemporary[i][j] = srcCoordinate[index];
index++;
}
}
// 根据用户输入的坐标信息计算出系数矩阵
double[][] ratio = new double[sum * 3][7];// 维数在此写死
int num = 0;// 记录当前存储的是第几行
for (int i = 0; i < sum; i++) {// sum组6
for (int j = 0; j < 3; j++) {// 每组三行
switch (j) {
case 0:
for (int k = 0; k < 7; k++) {// 每行七列
switch (k) {
case 0:
ratio[num][k] = 1;
break;
case 1:
ratio[num][k] = 0;
break;
case 2:
ratio[num][k] = 0;
break;
case 3:
ratio[num][k] = 0;
break;
case 4:
ratio[num][k] = -srcTemporary[i][2];// 取第i行的Z,加-
break;
case 5:
ratio[num][k] = srcTemporary[i][1];// 取第i行的Y
break;
case 6:
ratio[num][k] = srcTemporary[i][0];// 取第i行的X
break;
}
}
break;
case 1:
for (int k = 0; k < 7; k++) {// 每行七列
switch (k) {
case 0:
ratio[num][k] = 0;
break;
case 1:
ratio[num][k] = 1;
break;
case 2:
ratio[num][k] = 0;
break;
case 3:
ratio[num][k] = srcTemporary[i][2];// 取第i行的Z
break;
case 4:
ratio[num][k] = 0;
break;
case 5:
ratio[num][k] = -srcTemporary[i][0];// 取第i行的X
break;
case 6:
ratio[num][k] = srcTemporary[i][1];// 取第i行的Y
break;
}
}
break;
case 2:
for (int k = 0; k < 7; k++) {// 每行七列
switch (k) {
case 0:
ratio[num][k] = 0;
break;
case 1:
ratio[num][k] = 0;
break;
case 2:
ratio[num][k] = 1;
break;
case 3:
ratio[num][k] = -srcTemporary[i][1];// 取第i行的Y,加-
break;
case 4:
ratio[num][k] = srcTemporary[i][0];// 取第i行的X
break;
case 5:
ratio[num][k] = 0;
break;
case 6:
ratio[num][k] = srcTemporary[i][2];// 取第i行的Z
break;
}
}
break;
}
num++;
}
}
System.out.println("系数矩阵:");
for (int i = 0; i < sum * 3; i++) {
for (int j = 0; j < 7; j++) {
System.out.print(ratio[i][j] + " ");
}
System.out.print("\n");
}
// 根据用户输入的坐标信息计算出常数矩阵==========================
double[] temporary = new double[sum * 3];
for (int i = 0; i < srcCoordinate.length; i++) {
temporary[i] = (destCoordinate[i] - srcCoordinate[i]);
}
System.out.println("常数矩阵:");
for (int i = 0; i < sum * 3; i++) {
System.out.print(temporary[i] + " ");
}
System.out.print("\n");
double[][] ratioT = new double[7][sum * 3];//
// 获取矩阵转置
ratioT = MatrixOperating.transposition(ratio);
System.out.println("系数矩阵的转置:");
for (int j = 0; j < 7; j++) {
for (int i = 0; i < sum * 3; i++) {
System.out.print(ratioT[j][i] + " ");
}
System.out.print("\n");
}
// 经过最小二乘法变换方程组得到实际使用的矩阵a、b
double[][] resultA = MatrixOperating.multiplication(ratioT, ratio);
double[] resultB = MatrixOperating.multiplication(ratioT, temporary);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
a[i][j] = resultA[i - 1][j - 1];
for (int i = 1; i <= n; i++)
b[i] = resultB[i - 1];
Elimination();
Back();
Print();
Determinant();
// 校验数据
while (true) {
double[] checkSrc = new double[3];
System.out.println();
System.out.println("输入校验源坐标:");
for (int i = 0; i < checkSrc.length; i++) {
checkSrc[i] = as.nextDouble();
}
double[] checkDest = new double[3];
checkDest[0] = x[1] + (1 + x[7]) * (checkSrc[0]) - x[5]
* checkSrc[2] + x[6] * checkSrc[1];// X
checkDest[1] = x[2] + (1 + x[7]) * (checkSrc[1]) - x[6]
* checkSrc[0] + x[4] * checkSrc[2];// Y
checkDest[2] = x[3] + (1 + x[7]) * (checkSrc[2]) - x[4]
* checkSrc[1] + x[5] * checkSrc[0];// Z
System.out.println("结果目标坐标:");
for (int j = 0; j < checkDest.length; j++) {
System.out.print(checkDest[j] + " ");
}
}
}
}