684 lines
19 KiB
Dart
684 lines
19 KiB
Dart
|
// ignore_for_file: non_constant_identifier_names
|
|||
|
|
|||
|
import 'dart:math';
|
|||
|
|
|||
|
class CoordGPS {
|
|||
|
double LAT; //纬度
|
|||
|
double LNG; //经度
|
|||
|
double? ALT; //高度
|
|||
|
CoordGPS({this.ALT, required this.LAT, required this.LNG});
|
|||
|
}
|
|||
|
|
|||
|
class CoordXYH {
|
|||
|
double X;
|
|||
|
double Y;
|
|||
|
double H;
|
|||
|
CoordXYH({required this.X, required this.Y, required this.H});
|
|||
|
}
|
|||
|
|
|||
|
class CoordBLH {
|
|||
|
double B;
|
|||
|
double L;
|
|||
|
double H;
|
|||
|
CoordBLH({required this.B, required this.H, required this.L});
|
|||
|
}
|
|||
|
|
|||
|
class CoordXYZ {
|
|||
|
double X;
|
|||
|
double Y;
|
|||
|
double Z;
|
|||
|
CoordXYZ({required this.X, required this.Y, required this.Z});
|
|||
|
}
|
|||
|
|
|||
|
class PointXY {
|
|||
|
double X;
|
|||
|
double Y;
|
|||
|
PointXY({required this.X, required this.Y});
|
|||
|
}
|
|||
|
|
|||
|
class Region {
|
|||
|
double X;
|
|||
|
double Y;
|
|||
|
double? width;
|
|||
|
double? heigth;
|
|||
|
double? D;
|
|||
|
Region({this.D, required this.X, required this.Y, this.heigth, this.width});
|
|||
|
}
|
|||
|
|
|||
|
class Ellipsoid {
|
|||
|
late double A;
|
|||
|
late double F;
|
|||
|
late double B;
|
|||
|
late double E12;
|
|||
|
late double E22;
|
|||
|
Ellipsoid(String name) {
|
|||
|
const Map<String, Map<String, double>> datums = {
|
|||
|
'BJ54': {'a': 6378245, 'f': 1 / 298.3},
|
|||
|
'XA80': {'a': 6378140, 'f': 1 / 298.257},
|
|||
|
'WGS84': {'a': 6378137, 'f': 1 / 298.257223563},
|
|||
|
'WGS2000': {'a': 6378137, 'f': 1 / 298.257222101}
|
|||
|
};
|
|||
|
var Datum = datums[name];
|
|||
|
if (Datum != null) {
|
|||
|
double a = Datum['a']!;
|
|||
|
double f = Datum['f']!;
|
|||
|
double b = a - f * a;
|
|||
|
double e12 = (a * a - b * b) / (a * a); // 第一偏心率平方
|
|||
|
double e22 = (a * a - b * b) / (b * b); // 第二偏心率平方
|
|||
|
A = a;
|
|||
|
F = f;
|
|||
|
B = b;
|
|||
|
E12 = e12;
|
|||
|
E22 = e22;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class TransParm {
|
|||
|
late double dx;
|
|||
|
late double dy;
|
|||
|
late double dz;
|
|||
|
late double rx;
|
|||
|
late double ry;
|
|||
|
late double rz;
|
|||
|
late double rota;
|
|||
|
late double k;
|
|||
|
|
|||
|
TransParm(TransOptions options) {
|
|||
|
dx = options.dx ?? 0;
|
|||
|
dy = options.dy ?? 0;
|
|||
|
dz = options.dz ?? 0;
|
|||
|
rx = options.rx ?? 0;
|
|||
|
ry = options.ry ?? 0;
|
|||
|
rz = options.rz ?? 0;
|
|||
|
k = options.k ?? 0;
|
|||
|
rota = options.rota ?? 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class TransOptions {
|
|||
|
double? dx; //X平移(M)
|
|||
|
double? dy; //Y平移(M)
|
|||
|
double? dz; //z平移(M)
|
|||
|
double? rx; //X旋转(°)
|
|||
|
double? ry; //Y旋转(°)
|
|||
|
double? rz; //Z旋转(°)
|
|||
|
double? rota; //平面旋转,用于4参数
|
|||
|
double? k; //尺度(ppm)
|
|||
|
double? L0; //中央子午线(经度)
|
|||
|
String? srcEllipsoid; //源椭球名称
|
|||
|
String? dstEllipsoid; //目标椭球名称
|
|||
|
double? zoneWidth; //带宽度,用于未指定中央子午线时自动计算
|
|||
|
double? elevation; //投影高程
|
|||
|
TransOptions({
|
|||
|
this.L0,
|
|||
|
this.dstEllipsoid,
|
|||
|
this.dx,
|
|||
|
this.dy,
|
|||
|
this.dz,
|
|||
|
this.elevation,
|
|||
|
this.k,
|
|||
|
this.rota,
|
|||
|
this.rx,
|
|||
|
this.ry,
|
|||
|
this.rz,
|
|||
|
this.srcEllipsoid,
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
//主天线
|
|||
|
class CoordTrans {
|
|||
|
late double L0; //中央子午线
|
|||
|
late double zoneWidth; //带宽度
|
|||
|
late double elevation; //投影高程
|
|||
|
late double rota; //平面旋转,用于4参数
|
|||
|
late Ellipsoid srcEllipsoid; //源椭球
|
|||
|
late Ellipsoid dstEllipsoid; //目标椭球
|
|||
|
late TransParm transParm; //7参数
|
|||
|
CoordTrans(TransOptions options) {
|
|||
|
transParm = TransParm(options);
|
|||
|
L0 = options.L0 ?? 0;
|
|||
|
elevation = options.elevation ?? 0;
|
|||
|
srcEllipsoid = Ellipsoid(options.srcEllipsoid ?? 'WGS84');
|
|||
|
dstEllipsoid = Ellipsoid(options.dstEllipsoid ?? 'WGS2000');
|
|||
|
zoneWidth = options.zoneWidth ?? 3;
|
|||
|
}
|
|||
|
|
|||
|
CoordXYH GPS2XY(CoordGPS gps) {
|
|||
|
return d2p(CoordBLH(H: gps.ALT ?? elevation, B: gps.LAT, L: gps.LNG));
|
|||
|
}
|
|||
|
|
|||
|
//经纬度转平面坐标
|
|||
|
CoordXYH d2p(CoordBLH blh) {
|
|||
|
CoordXYZ zj = BLH2XYZ(blh);
|
|||
|
CoordXYZ xzj = XYZ2XYZ(zj);
|
|||
|
CoordBLH xdd = XYZ2BLH(xzj);
|
|||
|
CoordXYH xpm = BL2XY(xdd);
|
|||
|
return xpm;
|
|||
|
}
|
|||
|
|
|||
|
//平面坐标转大地坐标
|
|||
|
CoordBLH p2d(CoordXYH xyh) {
|
|||
|
CoordBLH bl = XY2BL(xyh, true);
|
|||
|
CoordXYZ zj = BLH2XYZ(bl, true);
|
|||
|
CoordXYZ xzj = XYZ2XYZ(zj, true);
|
|||
|
CoordBLH xdd = XYZ2BLH(xzj, true);
|
|||
|
return xdd;
|
|||
|
}
|
|||
|
|
|||
|
setZoneWidth(width) {
|
|||
|
if (width != 6 && width != 3) {
|
|||
|
// print('带宽应当为6或者为3');
|
|||
|
} else {
|
|||
|
zoneWidth = width;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
setL0(l0) {
|
|||
|
L0 = l0;
|
|||
|
}
|
|||
|
|
|||
|
int getZoneNo(double lng) {
|
|||
|
// 6度带
|
|||
|
// 这里应为向下取整
|
|||
|
if (zoneWidth == 6) {
|
|||
|
return ((lng + 6) / 6).floor();
|
|||
|
}
|
|||
|
// 3度带
|
|||
|
return ((lng + 1.5) / 3).floor();
|
|||
|
}
|
|||
|
|
|||
|
PointXY xy2xyLocal(PointXY source) {
|
|||
|
double x = source.X;
|
|||
|
double y = source.Y;
|
|||
|
double destx = x * transParm.k * cos(rota) -
|
|||
|
y * transParm.k * sin(rota) +
|
|||
|
transParm.dx;
|
|||
|
double desty = x * transParm.k * sin(rota) +
|
|||
|
y * transParm.k * cos(rota) +
|
|||
|
transParm.dy;
|
|||
|
|
|||
|
return PointXY(X: destx, Y: desty);
|
|||
|
}
|
|||
|
|
|||
|
CoordXYZ BLH2XYZ(CoordBLH pointBLH, [srcDst = false]) {
|
|||
|
Ellipsoid ellipsoid = srcDst ? srcEllipsoid : dstEllipsoid;
|
|||
|
double a = ellipsoid.A;
|
|||
|
double e12 = ellipsoid.E12;
|
|||
|
|
|||
|
double radB = pointBLH.B / 180 * pi;
|
|||
|
double radL = pointBLH.L / 180 * pi;
|
|||
|
double H = pointBLH.H;
|
|||
|
|
|||
|
double N = a / sqrt(1 - e12 * sin(radB) * sin(radB)); // 卯酉圈半径
|
|||
|
|
|||
|
double X = (N + H) * cos(radB) * cos(radL);
|
|||
|
double Y = (N + H) * cos(radB) * sin(radL);
|
|||
|
double Z = (N * (1 - e12) + H) * sin(radB);
|
|||
|
|
|||
|
return CoordXYZ(X: X, Y: Y, Z: Z);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
七参数转换
|
|||
|
不同椭球参数下, 地心直角坐标系之间转换
|
|||
|
dX, dY, dZ: 三个坐标方向的平移参数
|
|||
|
wX, wY, wZ: 三个方向的旋转角参数(单位为弧度)
|
|||
|
Kppm: 尺度参数, 单位是ppm,如果是以米为单位, 需要在传参前 除以1000000
|
|||
|
*/
|
|||
|
CoordXYZ XYZ2XYZ(CoordXYZ xyz, [srcDst = false]) {
|
|||
|
double X = xyz.X;
|
|||
|
double Y = xyz.Y;
|
|||
|
double Z = xyz.Z;
|
|||
|
double dX = transParm.dx;
|
|||
|
double dY = transParm.dy;
|
|||
|
double dZ = transParm.dz;
|
|||
|
double rX = transParm.rx / 3600 / 180 * pi;
|
|||
|
double rY = transParm.ry / 3600 / 180 * pi;
|
|||
|
double rZ = transParm.rz / 3600 / 180 * pi;
|
|||
|
double Kppm = transParm.k / 1000000;
|
|||
|
CoordXYZ result = CoordXYZ(X: 0, Y: 0, Z: 0);
|
|||
|
if (srcDst) {
|
|||
|
result.X = X - dX - Kppm * X + rY * Z - rZ * Y;
|
|||
|
result.Y = Y - dY - Kppm * Y - rX * Z + rZ * X;
|
|||
|
result.Z = Z - dZ - Kppm * Z + rX * Y - rY * X;
|
|||
|
} else {
|
|||
|
result.X = X + dX + Kppm * X - rY * Z + rZ * Y;
|
|||
|
result.Y = Y + dY + Kppm * Y + rX * Z - rZ * X;
|
|||
|
result.Z = Z + dZ + Kppm * Z - rX * Y + rY * X;
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
地心直角坐标系 转换到 地心大地坐标系
|
|||
|
用直接法2
|
|||
|
https://wenku.baidu.com/view/30a08f9ddd88d0d233d46a50.html
|
|||
|
*/
|
|||
|
CoordBLH XYZ2BLH(CoordXYZ XYZ, [srcDst = false]) {
|
|||
|
double X = XYZ.X;
|
|||
|
double Y = XYZ.Y;
|
|||
|
double Z = XYZ.Z;
|
|||
|
Ellipsoid ellipsoid = srcDst ? srcEllipsoid : dstEllipsoid;
|
|||
|
double a = ellipsoid.A;
|
|||
|
double b = ellipsoid.B;
|
|||
|
double e12 = ellipsoid.E12;
|
|||
|
double e22 = ellipsoid.E22;
|
|||
|
double L = atan(Y / X);
|
|||
|
// 弧度转角度
|
|||
|
double degL = L * 180 / pi;
|
|||
|
// Y值为正, 东半球, 否则西半球
|
|||
|
if (Y > 0) {
|
|||
|
while (degL < 0) {
|
|||
|
degL += 180;
|
|||
|
}
|
|||
|
while (degL > 180) {
|
|||
|
degL -= 180;
|
|||
|
}
|
|||
|
} else {
|
|||
|
while (degL > 0) {
|
|||
|
degL -= 180;
|
|||
|
}
|
|||
|
while (degL < -180) {
|
|||
|
degL += 180;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
double tgU = Z / (sqrt(X * X + Y * Y) * sqrt(1 - e12));
|
|||
|
double U = atan(tgU);
|
|||
|
|
|||
|
double tgB = (Z + b * e22 * pow(sin(U), 3)) /
|
|||
|
(sqrt(X * X + Y * Y) - a * e12 * pow(cos(U), 3));
|
|||
|
double B = atan(tgB);
|
|||
|
double degB = B * 180 / pi; // 弧度转角度
|
|||
|
if (Z > 0) {
|
|||
|
// Z值为正, 北半球, 否则南半球
|
|||
|
while (degB < 0) {
|
|||
|
degB += 90;
|
|||
|
}
|
|||
|
while (degB > 90) {
|
|||
|
degB -= 90;
|
|||
|
}
|
|||
|
} else {
|
|||
|
while (degB > 0) {
|
|||
|
degB -= 90;
|
|||
|
}
|
|||
|
while (degB < -90) {
|
|||
|
degB += 90;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
while (degB < 0) {
|
|||
|
degB += 360;
|
|||
|
}
|
|||
|
while (degB > 360) {
|
|||
|
degB -= 360;
|
|||
|
}
|
|||
|
|
|||
|
double N = a / sqrt(1 - e12 * sin(B) * sin(B)); // 卯酉圈半径
|
|||
|
double H = 0;
|
|||
|
// B接近极区, 在±90°附近
|
|||
|
if ((degB).abs() > 80) {
|
|||
|
H = Z / sin(B) - N * (1 - e12);
|
|||
|
} else {
|
|||
|
H = sqrt(X * X + Y * Y) / cos(B) - N;
|
|||
|
}
|
|||
|
return CoordBLH(B: degB, L: degL, H: H);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
地心大地坐标系 转换到 大地平面坐标系
|
|||
|
prjHeight: 投影面高程
|
|||
|
http://www.cnblogs.com/imeiba/p/5696967.html
|
|||
|
*/
|
|||
|
CoordXYH BL2XY(CoordBLH BLH,
|
|||
|
[srcDst = false, offsetY = 500000, offsetX = 0]) {
|
|||
|
Ellipsoid ellipsoid = srcDst ? srcEllipsoid : dstEllipsoid;
|
|||
|
double a = ellipsoid.A;
|
|||
|
double b = ellipsoid.B;
|
|||
|
double e12 = ellipsoid.E12;
|
|||
|
double e22 = ellipsoid.E22;
|
|||
|
if (L0 == 0) {
|
|||
|
int zoneNo = getZoneNo(BLH.L);
|
|||
|
L0 = (zoneNo - 0.5) * zoneWidth;
|
|||
|
}
|
|||
|
double radL0 = L0 / 180 * pi;
|
|||
|
|
|||
|
double radB = BLH.B / 180 * pi;
|
|||
|
double radL = BLH.L / 180 * pi;
|
|||
|
|
|||
|
double N = a / sqrt(1 - e12 * sin(radB) * sin(radB)); // 卯酉圈半径
|
|||
|
double T = tan(radB) * tan(radB);
|
|||
|
double C = e22 * cos(radB) * cos(radB);
|
|||
|
double A = (radL - radL0) * cos(radB);
|
|||
|
double M = a *
|
|||
|
((1 - e12 / 4 - 3 * e12 * e12 / 64 - 5 * e12 * e12 * e12 / 256) * radB -
|
|||
|
(3 * e12 / 8 + 3 * e12 * e12 / 32 + 45 * e12 * e12 * e12 / 1024) *
|
|||
|
sin(2 * radB) +
|
|||
|
(15 * e12 * e12 / 256 + 45 * e12 * e12 * e12 / 1024) *
|
|||
|
sin(4 * radB) -
|
|||
|
(35 * e12 * e12 * e12 / 3072) * sin(6 * radB));
|
|||
|
|
|||
|
//x,y的计算公式见孔祥元等主编武汉大学出版社2002年出版的《控制测量学》的第72页
|
|||
|
//书的的括号有问题,( 和 [ 应该交换
|
|||
|
|
|||
|
double x = M +
|
|||
|
N *
|
|||
|
tan(radB) *
|
|||
|
(A * A / 2 +
|
|||
|
(5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 +
|
|||
|
(61 - 58 * T + T * T + 600 * C - 330 * e22) *
|
|||
|
A *
|
|||
|
A *
|
|||
|
A *
|
|||
|
A *
|
|||
|
A *
|
|||
|
A /
|
|||
|
720);
|
|||
|
double y = N *
|
|||
|
(A +
|
|||
|
(1 - T + C) * A * A * A / 6 +
|
|||
|
(5 - 18 * T * T * T + 72 * C - 58 * e22) * A * A * A * A * A / 120);
|
|||
|
|
|||
|
x = offsetX + x * (b + elevation) / b;
|
|||
|
y = offsetY + y * (b + elevation) / b;
|
|||
|
|
|||
|
return CoordXYH(
|
|||
|
X: (x * 1000).round() / 1000, Y: (y * 1000).round() / 1000, H: BLH.H);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
大地平面坐标系 转换到 地心大地坐标系
|
|||
|
prjHeight: 投影面高程
|
|||
|
http://www.cnblogs.com/imeiba/p/5696967.html
|
|||
|
*/
|
|||
|
CoordBLH XY2BL(CoordXYH xyh,
|
|||
|
[srcDst = false, offsetY = 500000, offsetX = 0]) {
|
|||
|
Ellipsoid ellipsoid = srcDst ? srcEllipsoid : dstEllipsoid;
|
|||
|
double a = ellipsoid.A;
|
|||
|
double b = ellipsoid.B;
|
|||
|
double e12 = ellipsoid.E12;
|
|||
|
double e22 = ellipsoid.E22;
|
|||
|
|
|||
|
double e1 = (1 - sqrt(1 - e12)) / (1 + sqrt(1 - e12));
|
|||
|
double radL0 = L0 / 180 * pi;
|
|||
|
// 带内大地坐标
|
|||
|
double Y = xyh.Y % 1000000;
|
|||
|
double x = (xyh.X - offsetX) * b / (b + elevation);
|
|||
|
double y = (Y - offsetY) * b / (b + elevation);
|
|||
|
|
|||
|
double u = x /
|
|||
|
(a * (1 - e12 / 4 - 3 * e12 * e12 / 64 - 5 * e12 * e12 * e12 / 256));
|
|||
|
double fai = u +
|
|||
|
(3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * u) +
|
|||
|
(21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * u) +
|
|||
|
(151 * e1 * e1 * e1 / 96) * sin(6 * u) +
|
|||
|
(1097 * e1 * e1 * e1 * e1 / 512) * sin(8 * u);
|
|||
|
double C = e22 * cos(fai) * cos(fai);
|
|||
|
double T = tan(fai) * tan(fai);
|
|||
|
double N = a / sqrt(1 - e12 * sin(fai) * sin(fai));
|
|||
|
double R = a *
|
|||
|
(1 - e12) /
|
|||
|
sqrt((1 - e12 * sin(fai) * sin(fai)) *
|
|||
|
(1 - e12 * sin(fai) * sin(fai)) *
|
|||
|
(1 - e12 * sin(fai) * sin(fai)));
|
|||
|
double D = y / N;
|
|||
|
|
|||
|
double L = radL0 +
|
|||
|
(D -
|
|||
|
(1 + 2 * T + C) * D * D * D / 6 +
|
|||
|
(5 - 2 * C + 28 * T - 3 * C * C + 8 * e22 + 24 * T * T) *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D /
|
|||
|
120) /
|
|||
|
cos(fai);
|
|||
|
double B = fai -
|
|||
|
(N * tan(fai) / R) *
|
|||
|
(D * D / 2 -
|
|||
|
(5 + 3 * T + 10 * C - 4 * C * C - 9 * e22) *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D /
|
|||
|
24 +
|
|||
|
(61 + 90 * T + 298 * C + 45 * T * T - 256 * e22 - 3 * C * C) *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D *
|
|||
|
D /
|
|||
|
720);
|
|||
|
|
|||
|
B = B * 180 / pi;
|
|||
|
L = L * 180 / pi;
|
|||
|
return CoordBLH(B: B, L: L, H: xyh.H);
|
|||
|
}
|
|||
|
|
|||
|
//两点之间的距离公式
|
|||
|
dist(PointXY p1, PointXY p2) {
|
|||
|
double d = sqrt(pow((p2.X - p1.X), 2) + pow((p2.Y - p1.Y), 2));
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
//求坐标方位角
|
|||
|
double fwj(PointXY p1, PointXY p2) {
|
|||
|
double dx = p2.X - p1.X;
|
|||
|
double dy = p2.Y - p1.Y;
|
|||
|
return pi - sign(dy) - atan(dx / dy);
|
|||
|
}
|
|||
|
|
|||
|
// 计算三参数
|
|||
|
TransOptions calcThree(CoordBLH p1, CoordXYH p2) {
|
|||
|
CoordXYZ source = BLH2XYZ(p1);
|
|||
|
CoordBLH bl = XY2BL(p2, true);
|
|||
|
CoordXYZ dest = BLH2XYZ(bl, true);
|
|||
|
|
|||
|
double dX = dest.X - source.X;
|
|||
|
double dY = dest.Y - source.Y;
|
|||
|
double dZ = dest.Z - source.Z;
|
|||
|
return TransOptions(dx: dX, dy: dY, dz: dZ);
|
|||
|
}
|
|||
|
|
|||
|
// TransOptions calcFour(List p1, List p2, int PointCount) {
|
|||
|
// double rota = 0;
|
|||
|
// double scale = 0;
|
|||
|
// double dx = 0;
|
|||
|
// double dy = 0;
|
|||
|
// if (PointCount == 2) {
|
|||
|
// rota = fwj(p2[0] as PointXY, p2[1]) - fwj(p1[0], p1[1]);
|
|||
|
// scale = dist(p2[0], p2[1]) / dist(p1[0], p1[1]);
|
|||
|
// dx = p2[0].X - scale * cos(rota) * p1[0].X + scale * sin(rota) * p1[0].Y;
|
|||
|
// dy = p2[0].Y - scale * sin(rota) * p1[0].X - scale * cos(rota) * p1[0].Y;
|
|||
|
// } else if (PointCount > 2) {
|
|||
|
// double u = 1.0, v = 0, Dx = 0.0, Dy = 0.0;
|
|||
|
// int intCount = PointCount;
|
|||
|
|
|||
|
// Matrix4 dx1 = Matrix.zeros(4, 1);
|
|||
|
// // Matrix4 B1 = Matrix.zeros(2 * intCount, 4);
|
|||
|
// Matrix4 B1 = Matrix4.zero();
|
|||
|
// for (int i = 0; i < 2 * intCount; i++) {
|
|||
|
// for (int j = 0; j < 4; j++) {
|
|||
|
// B1.setEntry(i, j, 0);
|
|||
|
// }
|
|||
|
// }
|
|||
|
// Matrix4 W1 = Matrix.zeros(2 * intCount, 1);
|
|||
|
// // Matrix4 BT = Matrix.zeros(4, 2 * intCount);
|
|||
|
// Matrix4 BT = Matrix4.zero();
|
|||
|
// for (int i = 0; i < 4; i++) {
|
|||
|
// for (int j = 0; j < 2 * intCount; j++) {
|
|||
|
// BT.setEntry(i, j, 0);
|
|||
|
// }
|
|||
|
// }
|
|||
|
// Matrix4 N = Matrix4(
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// );
|
|||
|
// Matrix4 InvN = Matrix4(
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// 0,
|
|||
|
// );
|
|||
|
// Matrix4 BTW = Matrix.zeros(4, 1);
|
|||
|
// for (int i = 0; i < intCount; i++) {
|
|||
|
// //计算误差方程系数
|
|||
|
// B1.setEntry(2 * i, 0, 1);
|
|||
|
// B1.setEntry(2 * i, 1, 0);
|
|||
|
// B1.setEntry(2 * i, 2, p1[i].X);
|
|||
|
// B1.setEntry(2 * i, 3, -p1[i].Y);
|
|||
|
|
|||
|
// B1.setEntry(2 * i + 1, 0, 0);
|
|||
|
// B1.setEntry(2 * i + 1, 1, 1);
|
|||
|
// B1.setEntry(2 * i + 1, 2, p1[i].Y);
|
|||
|
// B1.setEntry(2 * i + 1, 3, p1[i].X);
|
|||
|
// // B1[2 * i][0] = 1;
|
|||
|
// // B1[2 * i][1] = 0;
|
|||
|
// // B1[2 * i][2] = p1[i].X;
|
|||
|
// // B1[2 * i][3] = -p1[i].Y;
|
|||
|
|
|||
|
// // B1[2 * i + 1][0] = 0;
|
|||
|
// // B1[2 * i + 1][1] = 1;
|
|||
|
// // B1[2 * i + 1][2] = p1[i].Y;
|
|||
|
// // B1[2 * i + 1][3] = p1[i].X;
|
|||
|
// }
|
|||
|
// for (int i = 0; i < intCount; i++) {
|
|||
|
// //计算误差方程系常数
|
|||
|
// // W1[2 * i][0] = p2[i].X - u * p1[i].X + v * p1[i].Y - Dx;
|
|||
|
// // W1[2 * i + 1][0] = p2[i].Y - u * p1[i].Y - v * p1[i].X - Dy;
|
|||
|
// W1.setEntry(2 * i, 0, p2[i].X - u * p1[i].X + v * p1[i].Y - Dx);
|
|||
|
// W1.setEntry(2 * i + 1, 0, p2[i].Y - u * p1[i].Y - v * p1[i].X - Dy);
|
|||
|
// }
|
|||
|
// // 最小二乘求解
|
|||
|
// Matrix4 b1 = Matrix4.identity();
|
|||
|
// // 矩阵 B1 的转置
|
|||
|
// BT = Matrix4.copy(b1);
|
|||
|
// BT.transpose();
|
|||
|
// // 矩阵乘法
|
|||
|
// N = BT * B1;
|
|||
|
// // 逆矩阵
|
|||
|
// InvN = N.clone();
|
|||
|
// InvN.invert();
|
|||
|
// BTW = BT * (W1);
|
|||
|
// dx1 = InvN * (BTW);
|
|||
|
|
|||
|
// Dx = Dx + dx1[0][0];
|
|||
|
// Dy = Dy + dx1[1][0];
|
|||
|
// u = u + dx1[2][0];
|
|||
|
// v = v + dx1[3][0];
|
|||
|
// dx = Dx;
|
|||
|
// dy = Dy;
|
|||
|
// rota = atan(v / u);
|
|||
|
// scale = u / cos(rota);
|
|||
|
// }
|
|||
|
// return TransOptions(rota: rota, k: scale, dx: dx, dy: dy);
|
|||
|
// }
|
|||
|
|
|||
|
// // 计算七参数
|
|||
|
// TransOptions calcBuras(List p1, List p2, pointCount) {
|
|||
|
// let B1 = Matrix.zeros(pointCount * 3, 7);
|
|||
|
// let dx1 = Matrix.zeros(7, 1);
|
|||
|
// let L = Matrix.zeros(pointCount * 3, 1);
|
|||
|
// let BT = Matrix.zeros(7, pointCount * 3);
|
|||
|
// let N = Matrix.zeros(7, 7);
|
|||
|
// let InvN = Matrix.zeros(7, 7);
|
|||
|
// let BTL = Matrix.zeros(7, 1);
|
|||
|
// for (int i = 0; i < pointCount * 3; i++) {
|
|||
|
// if (i % 3 == 0) {
|
|||
|
// L[i][0] = p2[(i / 3).floor()].X;
|
|||
|
// } else if (i % 3 == 1) {
|
|||
|
// L[i][0] = p2[(i / 3).floor()].Y;
|
|||
|
// } else if (i % 3 == 2) {
|
|||
|
// L[i][0] = p2[(i / 3).floor()].Z;
|
|||
|
// }
|
|||
|
// }
|
|||
|
|
|||
|
// for (int i = 0; i < pointCount * 3; i++) {
|
|||
|
// if (i % 3 == 0) {
|
|||
|
// int index = (i / 3) as int;
|
|||
|
// B1[i][0] = 1;
|
|||
|
// B1[i][1] = 0;
|
|||
|
// B1[i][2] = 0;
|
|||
|
// B1[i][3] = p1[index].X;
|
|||
|
// B1[i][4] = 0;
|
|||
|
// B1[i][5] = -p1[index].Z;
|
|||
|
// B1[i][6] = p1[index].Y;
|
|||
|
// } else if (i % 3 == 1) {
|
|||
|
// int index = ((i - 1) / 3) as int;
|
|||
|
// B1[i][0] = 0;
|
|||
|
// B1[i][1] = 1;
|
|||
|
// B1[i][2] = 0;
|
|||
|
// B1[i][3] = p1[index].Y;
|
|||
|
// B1[i][4] = p1[index].Z;
|
|||
|
// B1[i][5] = 0;
|
|||
|
// B1[i][6] = -p1[index].X;
|
|||
|
// } else if (i % 3 == 2) {
|
|||
|
// int index = ((i - 2) / 3) as int;
|
|||
|
// B1[i][0] = 0;
|
|||
|
// B1[i][1] = 0;
|
|||
|
// B1[i][2] = 1;
|
|||
|
// B1[i][3] = p1[index].Z;
|
|||
|
// B1[i][4] = -p1[index].Y;
|
|||
|
// B1[i][5] = p1[index].X;
|
|||
|
// B1[i][6] = 0;
|
|||
|
// }
|
|||
|
// }
|
|||
|
// Matrix4 b1 = Matrix4.identity();
|
|||
|
// BT = B1.transpose();
|
|||
|
// N = BT.mmul(B1);
|
|||
|
// InvN = inverse(N);
|
|||
|
// BTL = BT.mmul(L);
|
|||
|
// dx1 = InvN.mmul(BTL);
|
|||
|
|
|||
|
// double dx = dx1[0][0];
|
|||
|
// double dy = dx1[1][0];
|
|||
|
// double dz = dx1[2][0];
|
|||
|
// double scale = dx1[3][0];
|
|||
|
// double rotax = dx1[4][0] / dx1[3][0];
|
|||
|
// double rotay = dx1[5][0] / dx1[3][0];
|
|||
|
// double rotaz = dx1[6][0] / dx1[3][0];
|
|||
|
|
|||
|
// return TransOptions(
|
|||
|
// dx: dx, dy: dy, dz: dz, k: scale, rx: rotax, ry: rotay, rz: rotaz);
|
|||
|
// }
|
|||
|
|
|||
|
double sign(num number) {
|
|||
|
if (number < 0) {
|
|||
|
return -1.0;
|
|||
|
} else if (number > 0) {
|
|||
|
return 1.0;
|
|||
|
} else {
|
|||
|
return 0.0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|