先梳理一下两个概念:“国家统一坐标系“和”城市坐标系“
国家统一坐标系:此处可以认为是基于国家规定的大地椭球构建的球面坐标系(经纬度),经过高斯投影后形成的平面坐标系,各城市分属国家统一坐标系的不同分带坐标系中,此坐标是平面坐标,单位是长度单位,米或千米等
城市坐标系:在市政测绘中,工程制图和施工放样使用的都是大比例尺测绘数据,一般要求投影长度变形不大于2.5cm/km,国家统一坐标系很难满足需求,为此各地都建立了当地高精度的城市坐标系。此坐标是平面坐标,单位是长度单位,米或千米等。目前城市坐标系主要有以下两种。(1)与国家坐标系统一致的城市坐标系统(2)地方独立坐标系统。
针对上述两种城市坐标系,第一种由于和国家统一坐标系一致,测绘成果可以直接纳入国家统一坐标系。第二种独立于国家统一坐标系,要将此坐标系下的测绘成果纳入国家统一坐标系,就需要进行坐标转换。所以我们重点讨论的是城市坐标系中的第二种类型与国家统一坐标系之间的转换。属于两个平面坐标系之间的转换。
二维平面直角坐标之间的转换
两个二维平面直角坐标系的转换通常使用的是四参数模型,四参数适合小范围测区(5KM范围)的坐标转换。四参数转换模型公式如下:
在该模型中有四个未知参数,
(1)两个坐标平移量(△X,△Y),即两个平面坐标系的坐标原点之间的坐标差值。
(2)平面坐标轴的旋转角度,通过旋转一个角度,可以使两个坐标系的X和Y轴重合在一起。
(3)尺度因子K,即两个坐标系内的同一段直线的长度比值,实现尺度的比例转换。通常K值几乎等于1。
四个参数:△X,△Y,,m
已四参数,进行二维平面直角坐标之间的转换
按上述四参数转换模型公式,构建对应矩阵进行运算。即可求得转换后的目标坐标。相对比较简单,代码就不写了。需要用到矩阵,矩阵类库在《地理空间坐标系统-不同椭球基准间的坐标转换-相关算法代码实现C#》一节有分享。
未知四参数,通过两个以上的坐标点对反算四参数
反算四参数,常规做法是将四参数转换模型公式通过矩阵变换转换为复合最小二乘求解的矩阵表达式。简化过程如下(网上查找,高精度建议看相关论文):
此时的表达式符合B=AX的结构,可通过最小二乘公式进行求解:
未知四参数,通过两个以上的坐标点对反算四参数,代码实现C#
矩阵类库在《地理空间坐标系统-不同椭球基准间的坐标转换-相关算法代码实现C#》
///
///两个以上的坐标点对计算四参数
///
///
///
///
///
///
///
public static void CalFourParaByTwoPlaneRectangularCoords2(
Point2d[] originalCooords, Point2d[] targetCooords,
ref double rota, ref double scale,
ref double dx, ref double dy)
{
int pointCount = originalCooords.Length;
if (pointCount < 2)
{
//坐标点数小于三。
return;
}
if (targetCooords.Length < pointCount)
{
//新旧坐标个数不匹配
return;
}
double[,] pA = new double[pointCount * 2, 4];
double[,] pB = new double[pointCount * 2, 1];
for (int i = 0; i < pointCount * 2; i++)
{
if (i % 2 == 0)
{
pA[i, 0] = 1;
pA[i, 1] = 0;
pA[i, 2] = originalCooords[i / 2].X;
pA[i, 3] = -originalCooords[i / 2].Y;
}
else if (i % 2 == 1)
{
pA[i, 0] = 0;
pA[i, 1] = 1;
pA[i, 2] = originalCooords[i / 2].Y;
pA[i, 3] = originalCooords[i / 2].X;
}
}
///初始化B矩阵第一步
for (int i = 0; i < pointCount * 2; i++)
{
if (i % 2 == 0)
{
pB[i, 0] = targetCooords[i / 2].X - originalCooords[i / 2].X;
}
else if (i % 2 == 1)
{
pB[i, 0] = targetCooords[i / 2].Y - originalCooords[i / 2].Y;
}
}
GMatrix A = new GMatrix(pA);
GMatrix AT = A.Transpose();
GMatrix W = AT * A;
GMatrix W1 = W.Inverse();
GMatrix B = new GMatrix(pB);
GMatrix reslut = W1 * AT * B;
double X_offset, Y_offset, a1, a2;
X_offset = reslut[0, 0]; //x0
Y_offset = reslut[1, 0]; //y0
a1 = reslut[2, 0];
a2 = reslut[3, 0];
dx = X_offset; //x0
dy = Y_offset; //y0
rota = Math.Atan(a2 / (a1 + 1));
scale = (a1 + 1) / Math.Cos(rota);
}