七参数对不同坐标系统的转换

2 篇文章 0 订阅
1 篇文章 0 订阅

三参数法和七参数法均应用于空间直角坐标系的转换。

三参数坐标转换公式在假设两坐标系间各坐标轴相互平行,轴系间不存在欧勒角的条件下得出的。

【七参数】法:

如上图:两个空间直角坐标系分别为O1-X1Y1Z1与O2-X2Y2Z2,它们的原点不一致,相应的坐标轴相互不平行,两个坐标轴间除了三个平移参数,还有三个欧勒角,即三个旋转参数,又考虑到两个坐标系的尺度不尽一,还需设一个尺度变化参数m,总计共有七个参数。

用七参数进行空间直角坐标系转换有布尔莎公式、莫洛琴斯基公式和范式公式等。下面给出布尔莎七参数公式:

写成一般形式为:

七参数公式比较三参数公式能获得较高精度的转换结果。实际应用中,也可以舍弃不显著的参数,例如个别欧勒角,选择四、五或六个参数进行不同空间直角坐标系统的转换。

https://zhidao.baidu.com/question/1045966105464699179.html


了解坐标系

在大地测量学中,坐标系分为两大类:地心坐标系和参心坐标系。地心坐标系是坐标系原点与地球质心重合的坐标系,参心坐标系是坐标系原点位于参考椭球体中心,但不与地球质心重合的坐标系。我国使用的1954北京坐标系,1980西安坐标系都属于参心坐标系。GPS中使用的世界大地坐标系WGS84属于地心坐标系,我国最近开始启用的中国大地坐标系2000(即CGCS2000),也属于地心坐标系。以上两大类坐标系都有下列几种表达形式:1.空间大地坐标系,即大地经纬度(BLH形式2.空间直角坐标系,即三维空间坐标(XYZ)形式3.投影平面直角坐标系。即二维平面坐标(xyh)形式 在工程测量和施工中,我国普遍使用的是1954北京或1980西安的高斯投影平面直角坐标系。 但为满足工程施工精度要求,通常会在测区建立独立的地方坐标系,且独立地方坐标系都能够通过转换公式换算为国家统一的坐标系上,如1954北京坐标系或1980西安坐标系


1,大地坐标(BLH)对平面直角坐标(XYZ

常规的转换应先确定转换参数,即椭球参数、分带标准(3度,6度)和中央子午线的经度。椭球参数就是指平面直角坐标系采用什么样的椭球基准,对应有不同的长短轴及扁率。一般的工程中3度带应用较为广泛。对于中央子午线的确定有两种方法,一是取平面直角坐标系中Y坐标的前两位*3,即可得到对应的中央子午线的经度。如x=3250212my=395121123m,则中央子午线的经度=39*3=117度。另一种方法是根据大地坐标经度,如果经度是在155.5~185.5度之间,那么对应的中央子午线的经度=155.5+185.5/2=117度,其他情况可以据此3度类推。

另外一些工程采用自身特殊的分带标准,则对应的参数确定不在上述之列。

确定参数之后,可以用软件进行转换,以下提供坐标转换的程序下载。

2,北京54全国80WGS84坐标系的相互转换

这三个坐标系统是当前国内较为常用的,它们均采用不同的椭球基准。

其中北京54坐标系,属三心坐标系,大地原点在苏联的普而科沃,长轴6378245m,短轴6356863,扁率1/298.3;西安80坐标系,属三心坐标系,大地原点在陕西省径阳县永乐镇,长轴6378140m,短轴6356755,扁率1/298.25722101WGS84坐标系,长轴6378137.000m,短轴6356752.314,扁率1/298.257223563。由于采用的椭球基准不一样,并且由于投影的局限性,使的全国各地并不存在一至的转换参数。对于这种转换由于量较大,有条件的话,一般都采用GPS联测已知点,应用GPS软件自动完成坐标的转换。当然若条件不许可,且有足够的重合点,也可以进行人工解算。详细方法见第三类。

3.任意两空间坐标系的转换

由于测量坐标系和施工坐标系采用不同的标准,要进行精确转换,必须知道至少3个重合点(即为在两坐标系中坐标均为已知的点。采用布尔莎模型进行求解。布尔莎公式:

对该公式进行变换等价得到:

解算这七个参数,至少要用到三个已知点(2个坐标系统的坐标都知道),采用间接平差模型进行解算:

其中: V 为残差矩阵;

X 为未知七参数;

A 为系数矩阵;

解之:L 为闭合差

解得七参数后,利用布尔莎公式就可以进行未知点的坐标转换了,每输入一组坐标值,就能求出它在新坐标系中的坐标。 但是要想GPS观测成果用于工程或者测绘,还需要将地方直角坐标转换为大地坐标,最后还要转换为平面高斯坐标。

上述方法类同于我们的间接平差,解算起来较复杂,以下提供坐标转换程序,只需输入三个已知点的坐标即可求解出坐标转换的七个参数。如果已知点的数量较多,可以进行参数间的平差运算,则精度更高。

当已知点的数量只有两个时,我们可以采用简单变换法,此法较为方便易行,适于手算,只是精度受到一定的限制。

详细解算方程如下:

式中调x,yx\'y\'分别为新旧(或;旧新)网重合点的坐标,ab、、k为变换参数,显然要解算出ab、、k,必须至少有两个重合点,列出四个方程。

即可进行通常的参数平差,解求axbcd各参数值。将之代人(3)式,可得各拟合点的残差(改正数)代人(2)式,可得待换点的坐标。

求出解算参数之后,可输入源坐标进行目标坐标的转换。

http://blog.163.com/zhzh_212/blog/static/505580332008111142523910/


课外了解

http://blog.csdn.net/findsafety/article/details/12442639

一、各个坐标系的概况

        众所周知地球是一个不规则椭圆体,GIS中的坐标系定义由基准面和地图投影两组参数确定,而基准面的定义则由特定椭球体及其对应的转换参数确定。 基准面是利用特定椭球体对特定地区地球表面的逼近,因此每个国家或地区均有各自的基准面。基准面是在椭球体基础上建立的,椭球体可以对应多个基准面,而基准面只能对应一个椭球体。意思就是无论是谷歌地图、搜搜地图还是高德地图、百度地图区别只是针对不同的大地地理坐标系标准制作的经纬度,不存在准不准的问题,大家都是准的只是参照物或者说是标准不一样。谷歌地图采用的是WGS84地理坐标系(中国范围除外),谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系,百度采用的是BD09坐标系,而设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,为什么不统一用WGS84地理坐标系这就是国家地理测绘总局对于出版地图的要求,出版地图必须符合GCJ02坐标系标准了,也就是国家规定不能直接使用WGS84地理坐标系。所以定位大家感觉不准确很多又叫出版地图为火星地图其实只是坐标系不一样而已。这就是为什么设备采集的经纬度在地图上显示的时候经常有很大的偏差,远远超出民用GPS 10米偏移量的技术规范。

以上参考自:haotsp.com 


总结:

WGS84坐标系:即地球坐标系,国际上通用的坐标系。

GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。

BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。

搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。

 

二、各个地图API采用的坐标系

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] + "    ");
}
}
}
}


 

                
  • 13
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值