闭合导线平差

c++间接平差法对闭合导线进行平差

环境:vs2017+qt+eigen-3.3.8

对源代码文件读取和输出进行适当修改可以不搭配qt工具

算法

(1)基本公式

(2)对角度和边长观测值进行线性化

角度值:

边长值:

程序介绍

ui界面

 示例数据:

90, 30, 49.73
268, 10, 9.48
94, 6, 33.22
87, 54, 54.23
180, 17, 42.47
90, 57, 23.22
179, 20, 51.72
89, 14, 10.73
132, 10, 25.47
227, 16, 59.73
200.78625
51.02175
110.6125
198.17775
276.3395
166.78125
200.0075
128.38675
65.24225
258.52325

 只适合如图所示的闭合导线类型(即不带支导线)数据仅供参考

代码

头文件:

#pragma once

#include <QtWidgets/QWidget>
#include "ui_horizontal_control_network.h"

class horizontal_control_network : public QWidget
{
    Q_OBJECT

public:
    horizontal_control_network(QWidget *parent = nullptr);
	int compute();
    ~horizontal_control_network();

private:
    Ui::horizontal_control_networkClass ui;
};

mian函数

#include "horizontal_control_network.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    horizontal_control_network w;
    w.show();
    return a.exec();
}

 主要计算函数

int horizontal_control_network::compute()函数为窗口响应函数

#include "horizontal_control_network.h"
#include<qpushbutton.h>
#include<qmessagebox.h>
#include <QTextEdit>  
#include <QStringList>  
#include<qdebug.h>
#include<cmath>
#include<Eigen/Dense>
#include<stdio.h>
#include<iostream>
#include <QFileDialog>   //文件对话框
#include <fstream>
#define PI acos(-1)

//根据反正切值、delta_y\delta_x返回边长方位角
double pd(double fw, double deltay, double deltax) {
	if (fw > 0) {
		if (deltay > 0 && deltax > 0)return fw;
		else if (deltay < 0 && deltax <0) {
			return PI + fw;
		}
		else {
			return fw;
		}
	}
	else if(fw<0){
		if (deltay < 0 && deltax>0)return 2 * PI + fw;
		else if(deltay >0 && deltax<0)return PI +fw;
		else return  fw + 2 * PI;
	}
	else if((int)(fw*1e10)==0){
		if(deltax<0 ) return PI;
		else return 0;
	}
}
//double类型的数据做等于判断
bool dy(double a,double b) {
	if (int(a*1e10) == int(b*1e10)) return true;
	else return 0;
}
//根据两个坐标方位角,求出之间的夹角
double pda(double a, double b) {
	double jiao;
	if (a - b < 0)return a - b + 2 * PI;
	else return a +b;
}
using namespace std;
//转换角度 ,单位秒 
double tsa(double a, double b, double c) { return a * 3600 + b * 60 + c; }
//转换角度,单位度
double tsan(double a, double b, double c) { return a + b / 60 + c / 3600; }
double yushu(double x, int a) {//double类型的做余数
	double f = x - (int)x;
	int b = (int)x;
	int z = (b %= a);
	return z + f;
}
//让方位角的角度变为正数
void pn(double fw[20][3], int i) {
	int a, b, c, y, j;
	double sum;
	for (j = 0; j < i; j++) {
		sum = fw[j][0] * 3600 + fw[j][1] * 60 + fw[j][2];
		if (fw[j][0] < 0) {
			y = (-sum) / 360 / 3600;
			sum = sum + (y + 1) * 360 * 3600;
		}
		fw[j][0] = (int)(sum / 3600), sum = yushu(sum, 3600);
		fw[j][1] = (int)(sum / 60), sum = yushu(sum, 60);
		fw[j][2] = sum;
	}
}
//求两点之间的距离
double enorm(double x1, double y1, double x2, double y2) {
	return  sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}

horizontal_control_network::horizontal_control_network(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
	//读取文件并输出按钮的槽函数
	connect(ui.pushButton_2, &QPushButton::clicked, this, [=] {
		compute();
	});
	//清空
	connect(ui.pushButton_3, &QPushButton::clicked, this, [=]() {
		ui.lineEdit->clear();
		ui.lineEdit_2->clear();
		ui.lineEdit_3->clear();
		ui.lineEdit_4->clear();
	});
	//退出功能
	connect(ui.pushButton_4, &QPushButton::clicked, this, &QWidget::close);

}

int horizontal_control_network::compute()//计算函数
{
	int n, i = 0, j = 0, chose = 1;
	double rou = 180 / PI * 3600;
	n = ui.lineEdit->text().toInt();
	//初始化二维数组
	double s[20],fwj[20],xy[20][2],angle[20][3] ,fw[20][3];

	if (ui.lineEdit->text().isEmpty()) {
		QMessageBox::critical(this, "warning", "Please input the number of edges");
		return 0;
	}
	//判断已知数据是否为空,并赋值
	if (ui.lineEdit_2->text().isEmpty()) { xy[0][0] = 0; }
	else { xy[0][0] = ui.lineEdit_2->text().toDouble(); }
	if (ui.lineEdit_3->text().isEmpty()) { xy[0][1] = 0; }
	else { xy[0][1] = ui.lineEdit_3->text().toDouble(); }
	if (ui.lineEdit_4->text().isEmpty()) { fw[0][0] = 0; fw[0][1] = 0; fw[0][2] = 0; }
	else {
		QString fw0 = ui.lineEdit_4->text();
		QStringList flist = fw0.split(','); i = 0;
		for (QString str : flist) { fw[0][i] = str.toDouble(); i++; }
		if (i != 3) {
			QMessageBox::critical(this, "warning", "The beginning azimuth's format error");
			return 0;
		}
	}


	if (ui.radioButton_2->isChecked()) chose = 2;

	//文件对话框
	QString in_path = QFileDialog::getOpenFileName(this, "OPEN", "../", "TXT(*.txt)");//设置文件路径 文件格式
	if (in_path.isEmpty() == false) {//路径正确
		//创建文件对象 并且关联起来
		QFile file(in_path);
		bool isok = file.open(QIODevice::ReadOnly);//利用只读模式打开文件
		if (isok) {//打开成功
			QString text = file.readAll();//换行符号也是读取的
			QStringList list = text.split('\n');// 使用换行分隔字符串,将其转换为QStringList  
			i = 0;
			for (QString str : list) {
				if (i < n) {//读取角度观测值
					QStringList list1 = str.split(',');
					j = 0;
					for (QString str1 : list1) {
						angle[i][j] = str1.toDouble();
						j++;
					}
					if (j != 3) {
						QMessageBox::critical(this, "warning", "Angle format error"); file.close();return 0;
					}
				}
				else {//读取边长观测值
					s[i - n] = str.toDouble();
				}
				i++;
			}
			if (i != 2 * n) {
				QMessageBox::critical(this, "warning", "data error"); file.close();return 0;
			}

		}
		else {
			QMessageBox::critical(this, "warning", "Failed to open observation data file, exiting function"); file.close(); return 0;
		}
	}
	else {
		QMessageBox::critical(this, "warning", "The observation data file path is empty"); return 0;
	}
	//fwj[0] = fw[0][0] + fw[0][1] / 60 + fw[0][2] / 3600;
		//储存初始方位角 
		if (chose == 1)
			for (j = 1; j < n; j++) {
				fw[j][0] = (int)fw[j - 1][0] + 180 - angle[j][0], fw[j][1] = (int)fw[j - 1][1] - angle[j][1], fw[j][2] = fw[j - 1][2] - angle[j][2];
			}
		else
			for (j = 1; j < n; j++) {
				fw[j][0] = (int)fw[j - 1][0] - 180 + angle[j][0], fw[j][1] = angle[j][1] + (int)fw[j - 1][1], fw[j][2] = angle[j][2] + fw[j - 1][2];
			}

			//保证角度格式
		for (j = 0; j < n; j++) {
			if (fw[j][2] >= 60) fw[j][1] += (int)(fw[j][2] / 60), fw[j][2] = yushu(fw[j][2], 60);
			if (fw[j][1] >= 60) fw[j][0] += (int)(fw[j][1] / 60), fw[j][1] = (int)(yushu(fw[j][1], 60));
			if (fw[j][2] <= -60) fw[j][1] += (int)(fw[j][2] / 60), fw[j][2] = -yushu(abs(fw[j][2]), 60);
			if (fw[j][1] <= -60) fw[j][0] += (int)(fw[j][1] / 60), fw[j][1] = (int)(-yushu(abs(fw[j][1]), 60));
		}
		 pn(fw, n);//该函数是将负的分、秒值改正

		for (j = 0; j < n; j++) fwj[j] = fw[j][0] + fw[j][1] / 60 + fw[j][2] / 3600;
		//起始方位角不能输入90度或270度
		if (dy(fwj[0], 90)||dy(fwj[0],270)) {
			QMessageBox::critical(this, "warning", "Please do not enter an azimuth angle of 90 degrees or 270 degrees"); return 0;
		}

		//计算近似坐标
		for (j = 1; j < n; j++) {
			xy[j][0] = xy[j - 1][0] + s[j - 1] * cos(fwj[j - 1]/180*PI);
			xy[j][1] = xy[j - 1][1] + s[j - 1] * sin(fwj[j - 1]/180*PI);
		}

		//误差方程系数的计算
			//创建矩阵,并初始化为0矩阵
		Eigen::MatrixXd l = Eigen::MatrixXd::Zero(2 * n , 1);
		Eigen::MatrixXd L = Eigen::MatrixXd::Zero(2 * n , 1);
		Eigen::MatrixXd B = Eigen::MatrixXd::Zero(2 * n , 2 * n - 3);
		Eigen::MatrixXd P = Eigen::MatrixXd::Zero(2 * n , 2 * n );
		Eigen::MatrixXd X = Eigen::MatrixXd::Zero(2 * n - 3, 1);//参数近似值矩阵
		//近似参数赋值
		//把第2个点的x坐标当做参数
		X(0, 0) = xy[1][0];
		for (i = 2; i < n; i++) {
			X(2 * (i - 2)+1, 0) = xy[i][0];
			X(2 * (i - 2) + 2, 0) = xy[i][1];
		}

		//边长近似值和常数向量赋值
		//边长近似值
		for (i = n; i < 2 * n ; i++) {
			if (i == 2 * n - 1) {
				L(i) = enorm(xy[i - n ][0], xy[i - n ][1], xy[0][0], xy[0][1]);
			}
			else
				L(i) = enorm(xy[i - n ][0], xy[i - n ][1], xy[i - n +1][0], xy[i - n +1][1]);
			l(i) = (s[i - n ] - L(i))*1000;//单位毫米
		}


		//角度观测值系数的计算
			//L向量和l向量赋值
		for (i = 0; i < n; i++) {
			double a, b,day,dax,dby,dbx;
			if (i == 0) {
				a = atan((xy[n - 1][1] - xy[0][1]) / (xy[n - 1][0] - xy[0][0])); day = xy[n - 1][1] - xy[0][1]; dax = xy[n - 1][0] - xy[0][0];
				b = atan((xy[1][1] - xy[0][1]) / (xy[1][0] - xy[0][0])); dby = xy[1][1] - xy[0][1]; dbx = xy[1][0] - xy[0][0];
			}
			else if (i == n - 1) {
				a = atan((xy[n - 2][1] - xy[n - 1][1]) / (xy[n - 2][0] - xy[n - 1][0])); day = xy[n - 2][1] - xy[n - 1][1]; dax = xy[n - 2][0] - xy[n - 1][0];
				b = atan((xy[0][1] - xy[n - 1][1]) / (xy[0][0] - xy[n - 1][0])); dby = xy[0][1] - xy[n - 1][1]; dbx = xy[0][0] - xy[n - 1][0];
			}
			else {
				a = atan((xy[i - 1][1] - xy[i][1]) / (xy[i - 1][0] - xy[i][0])); day = xy[i - 1][1] - xy[i][1]; dax = xy[i - 1][0] - xy[i][0];
				b = atan((xy[i + 1][1] - xy[i][1]) / (xy[i + 1][0] - xy[i][0])); dby = xy[i + 1][1] - xy[i][1]; dbx = xy[i + 1][0] - xy[i][0];
			}
			a = pd(a, day, dax);//确定后视边长方位角
			b = pd(b, dby, dbx);
			if(chose==1) L(i) = pda(a ,b);//单位弧度
			else L(i) = pda(b, a);
			P(i, i) = 1;//权阵赋值
		}
		//改正角度正负号
		/*for (i = 0; i < n; i++) {
			double ch = L(i)*180/PI;
			if ((int)(L(i) * 180 / PI) != angle[i][0]) {
				QMessageBox::critical(this, "warning", "Angle sign correction error"); return 0;
			};
		}*/
		//观测值-近似值
		for (i = 0; i < n; i++) {
			l(i) = (tsan(angle[i][0], angle[i][1], angle[i][2])*PI / 180 - L(i))*rou;//弧度秒
		}
		//B矩阵赋值
		/*在闭合圈中i为循环遍历所在点(角);
		又因为第一点xy[0][0],xy[0][1]和第二点的xy[1][1]为已知点,其微分值为0,当其有计算程序时,需要分类讨论
		并且B矩阵的第一列参数应从第二点的x坐标开始,
		j为当前点的x坐标参数在B矩阵的列的索引,k为后视点x坐标索引,h为前视点x坐标索引
		*/
			for (i = 0; i < n; i++) {
			int j, k, h;
			j = 2 * (i - 2)+1, k = 2 * (i - 2)-1, h = 2 * (i - 2) + 3;//i>=3
			if (i == 0) {
				B(i, 2 * n - 5) = -rou / pow(L(2*n - 1), 2)*(xy[n - 1][1] - xy[0][1])/1000;
				B(i, 2 * n - 4) = rou / pow(L(2 * n - 1), 2)*(xy[n - 1][0] - xy[0][0]) / 1000;
				B(i, 0) = rou / pow(s[0], 2)*(xy[1][1] - xy[0][1]) / 1000;
			}
			else if (i == n - 1) {
				B(i, 2 * n - 5) = rou * ((xy[n - 2][1] - xy[n - 1][1]) / pow(L(2 * n - 2), 2) - (xy[0][1] - xy[n - 1][1]) / pow(L(2 * n - 1), 2)) / 1000;
				B(i, 2 * n - 4) = -rou * ((xy[n - 2][0] - xy[n - 1][0]) / pow(L(2 * n - 2), 2) - (xy[0][0] - xy[n - 1][0]) / pow(L(2 * n - 1), 2)) / 1000;
				B(i, 2 * n - 7) = -rou / pow(L(2 * n - 2), 2)*(xy[n - 2][1] - xy[n - 1][1]) / 1000;
				B(i, 2 * n - 6) = rou / pow(L(2 * n - 2), 2)*(xy[n - 2][0] - xy[n - 1][0]) / 1000;
			}
			else if (i == 1) {
				B(i, 0) = rou * ((xy[0][1] - xy[1][1]) / pow(s[0], 2) - (xy[2][1] - xy[1][1]) / pow(L(n+1), 2)) / 1000;
				B(i, 1) = rou / pow(L(n+1), 2)*(xy[2][1] - xy[1][1]) / 1000;
				B(i, 2) = -rou / pow(L(n+1), 2)*(xy[2][0] - xy[1][0]) / 1000;
			}
			else if (i == 2) {
				B(i, j) = rou * ((xy[i - 1][1] - xy[i][1]) / pow(L(n + i - 1), 2) - (xy[i + 1][1] - xy[i][1]) / pow(L(n + i ), 2)) / 1000;
				B(i, j + 1) = -rou * ((xy[i - 1][0] - xy[i - 1][0]) / pow(L(n + i -1), 2) - (xy[i + 1][0] - xy[i][0]) / pow(L(n + i ), 2)) / 1000;
				B(i, 0) = -rou / pow(L(n + i -1), 2)*(xy[i - 1][1] - xy[i][1]) / 1000;
				B(i, h) = rou / pow(L(n + i ), 2)*(xy[i + 1][1] - xy[i][1]) / 1000;
				B(i, h + 1) = -rou / pow(L(n + i ), 2)*(xy[i + 1][0] - xy[i][0]) / 1000;
			}
			else {
				B(i, j) = rou * ((xy[i - 1][1] - xy[i][1]) / pow(L(n + i - 1), 2) - (xy[i + 1][1] - xy[i][1]) / pow(L(n+i), 2)) / 1000;
				B(i, j + 1) = -rou * ((xy[i - 1][0] - xy[i - 1][0]) / pow(L(n + i - 1), 2) - (xy[i + 1][0] - xy[i][0]) / pow(L(n + i ), 2)) / 1000;
				B(i, k) = -rou / pow(L(n + i - 1), 2)*(xy[i - 1][1] - xy[i][1]) / 1000;
				B(i, k + 1) = rou / pow(L(n + i - 1), 2)*(xy[i - 1][0] - xy[i][0]) / 1000;
				B(i, h) = rou / pow(L(n + i ), 2)*(xy[i + 1][1] - xy[i][1]) / 1000;
				B(i, h + 1) = -rou / pow(L(n + i ), 2)*(xy[i + 1][0] - xy[i][0]) / 1000;
			}

		}
		//距离观测值系数计算
		for (i = n; i < 2 * n ; i++) {
			//B矩阵系数赋值
			int j = 2 * (i - n-1)-1, h = 2 * (i - n -1)+1;//i>n+1;j为后视点,h为前视点
			if (i == 2 * n - 1) {
				B(i, j) = -(xy[0][0] - xy[i - n ][0]) / L(i);
				B(i, j + 1) = -(xy[0][1] - xy[i - n ][1]) / L(i);
			}
			else if (i==n) {
				B(i, 0) = (xy[1][0]-xy[0][0] ) / L(i);
			}
			else if (i == n + 1) {
				B(i, 0) = -(xy[i - n + 1][0] - xy[i - n][0]) / L(i);
				B(i, h) = (xy[i - n + 1][0] - xy[i - n][0]) / L(i);
				B(i, h + 1) = (xy[i - n + 1][1] - xy[i - n][1]) / L(i);
			}
			else {
				B(i, j) = -(xy[i - n +1][0] - xy[i - n ][0]) / L(i);
				B(i, j + 1) = -(xy[i - n +1][1] - xy[i - n][1]) / L(i);
				B(i, h) = (xy[i - n +1][0] - xy[i - n ][0]) / L(i);
				B(i, h + 1) = (xy[i - n+1 ][1] - xy[i - n ][1]) / L(i);
			}
			//权阵
			P(i, i) = 1/ pow((2 + 3 * L(i)*1e-3), 2);
		}

		//矩阵解算
		Eigen::MatrixXd NBB(2 * n - 3, 2 * n - 3);
		Eigen::MatrixXd x(2 * n - 3, 1);
		Eigen::MatrixXd v(2 * n , 1);
		Eigen::MatrixXd L_(2 * n , 1);
		Eigen::MatrixXd QXX(2 * n - 3, 2*n-3);
		Eigen::MatrixXd DXX(2 * n - 3, 2 * n - 3);
		NBB = B.transpose()*P*B;
		QXX = NBB.inverse();
		x = NBB.inverse()*B.transpose()*P*l;//毫米

		//当起始方位角为90度或270度时,将第2个坐标的y值变为参数,x置零

		v = B * x - l;//角度为弧度秒,距离是毫米
		Eigen::MatrixXd zh(1,1);//从一行一列矩阵提取单位权中误差所需数字
		zh= v.transpose()*P*v;
		double jm = zh(0, 0);
		double o = sqrt(jm/3);//单位权中误差
		//创建文件并输出
		QString filePath = QFileDialog::getSaveFileName(this, "Save As", "E:/output", tr("TXT(*.txt)"));
		QByteArray mstr = filePath.toLocal8Bit();
		std::string path = std::string(mstr);//将qstring(包含中文)转换为string

		ofstream out_file(path);
		if (out_file.is_open()) {
			out_file << "单位权中误差为(mm):" << std::endl;
			out_file << to_string(o) << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "观测值近似值矩阵为(角度观测值单位为弧度,边长单位为米):" << std::endl;
			out_file << L << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "参数近似值矩阵为(单位米):" << std::endl;
			out_file << X << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "B矩阵为:" << std::endl;
			out_file << B << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "l矩阵为:" << std::endl;
			out_file << l << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "权阵P矩阵为:" << std::endl;
			out_file << P << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "x参数改正数矩阵矩阵为单位为mm:" << std::endl;
			out_file << x << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "v观测值改正数矩阵(角度观测值单位为秒,边长单位为毫米)为:" << std::endl;
			out_file << v << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			for (i = 0; i < n; i++) {
				L_(i, 0) = angle[i][0] + angle[i][1] / 60 + (angle[i][2] + v(i, 0)) / 3600;
			}
			for (i = n; i < 2*n; i++) {
				L_(i, 0) = s[i-n]+v(i,0)/1000;
			}
			out_file << "改正后的观测阵矩阵为(角度观测值单位为度,边长单位为米):" << std::endl;
			out_file << L_ << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			X = X + x/1000;
			out_file << "改正后的参数矩阵为:(单位m)" << std::endl;
			out_file << X<< std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "协因数阵QXX为:(单位mm)" << std::endl;
			out_file << QXX << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;
			out_file << "方差协方差阵DXX为:(单位mm)" << std::endl;
			DXX = QXX * o;
			out_file << DXX << std::endl;
			out_file << "--------------------------------------------------------------------" << std::endl;

		}
		else {
			QMessageBox::critical(this, "warning", "The outfile is not opened!"); return 0;
		};
		out_file.close();
		return 0;
}

horizontal_control_network::~horizontal_control_network()
{
}

附: 

上述示例数据测量误差非常大,仅供运行。

下面的数据是我自己编的近似正五边形,可以代替示例

108,0,4
108,0,3
108,0,1
107,59,58
108,0,1
100.009
100
100.005
100.004
100

输出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值