这是湖南某高校的一次遥感程序设计实践,共十天时间,博主在经历了八天的实习后进行答辩,学长学姐都是MFC的运行环境,从博主这一届开始都是用QT,但关于QT运行环境的文章远远不够,所以博主想写这篇文章,既记录自己的实习感想又给学弟学妹一点启发。
特别提醒:
博主只是学生,不喜勿喷,出门左拐,还有很多优秀博主的优质的相关文章可以供大家参考。
1.需求分析
1.导线网间接平差
<1>.读取数据文件
<2>.对读取的观测数据进行近似计算(概算)
<3>.对概算后的坐标进行间接平差迭代
<4>.输出平差后的精度
2.网形绘制与误差椭圆
<1>.绘制网格与坐标轴
<2>.绘制已知点和未知点构成的导线网
<3>.绘制点名
<4>.绘制误差椭圆与已知点标识
<5>.网格数和误差椭圆比例的参数调整
<6>.隐藏误差椭圆
3.保存结果文件
<1>.输出文档
2. 控制网平差原理
采用的是间接平差:设置的未知数便是最终要平差解算的结果,一个观测值便要对应一个误差方程,将所有的观测误差方程列为一个观测方程组,再将它提取成为一个矩阵方程式。











3.系统架构与模块划分
1.系统架构
程序主要由数据读取、概算计算、平差计算和绘图显示四个核心部分组成
2.模块划分
<1>.数据模型模块
KZW 类:负责存储导线网的各种数据,包括点、边长、角度等信息,同时提供概算、平差计算的方法。
关键成员:
QVector<Point> points:存储所有点的信息。
QVector<Length> lengths:存储所有边长观测信息。
QVector<include_Angle> iangles:存储所有夹角观测信息。
QVector<ce_Angle> cangles:存储所有方位角观测信息。
void gaisuan():概算函数,用于计算未知点的坐标。
double pingcha():平差函数,进行间接平差计算并进行精度评定。
<2>.数据读取模块
MainWindow 类的readSurveyData方法:从指定文件中读取导线网的观测数据,包括已知点、未知点、边长和角度信息,并将数据存储到KZW对象中。
<3>.执行逻辑模块
MainWindow 类:作为程序的主窗口,提供用户界面和交互功能,处理用户的操作请求,如概算计算、平差计算和跳转绘图界面等
<4>.绘图显示模块
Draw_net_ellipse 类:负责绘制导线网的图形,包括坐标系、网格、导线边、点和误差椭圆等。
4.代码
1.mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "draw_net_ellipse.h"//这是绘图页面对应类的头文件
#include <QMainWindow>
#include <QFileDialog>
#include "kzw.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
KZW kzw; // 添加KZW类实例
Draw_net_ellipse *ppage2=NULL;//用来保存绘图页面的实例化对象的地址
bool getFilePath (QStringList &strListInputPath);
bool readSurveyData(const QString& filePath) ;
private slots:
void on_read_originaldata_Button_clicked();
void on_budget_estimate_Button_clicked();
void on_indirect_adjustment_Button_clicked();
void on_jump_drawing_interface_Button_clicked();
void on_quit_Button_clicked();
void on_save_Button_clicked();
void on_check_pushButton_clicked();
void on_clear_Button_clicked();
private:
QStringList mInputPath; //文件路径
Ui::MainWindow *ui;
signals://信号
void send(KZW);//发送者
};
#endif // MAINWINDOW_H
2.mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::getFilePath(QStringList &strListInputPath)
{
QFileDialog *fileDialog = new QFileDialog(this);
fileDialog->setWindowTitle(QStringLiteral("选择文件"));
fileDialog->setDirectory("./");
fileDialog->setNameFilter(tr("File(*dat)"));
fileDialog->setViewMode(QFileDialog::Detail);
if (fileDialog->exec())
{
strListInputPath = fileDialog->selectedFiles();
}
if (strListInputPath.size() != 0)
return true;
else
return false;
}
bool MainWindow::readSurveyData(const QString& filePath)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "文件打开失败:" << filePath;
return false;
}
QTextStream in(&file);
QString line;
kzw.points.clear(); // 清空现有数据
kzw.lengths.clear();
kzw.iangles.clear();
// 读取已知点数量
line = in.readLine().trimmed();
if (line.isEmpty())
{
QMessageBox::critical(this, "数据错误", "已知点数量行不能为空!");
file.close();
return false;
}
QList<QString> data;//存储逐行读取的数据
int yzdn = line.toInt();
for(int i = 0;i<yzdn;i++)
{
line= in.readLine().trimmed();
data=line.split(',');
//错误检验
if(data.size()>3)
{
QMessageBox::critical(this,"Critical",tr("读取的已知点数据格式有问题"));
}
kzw.points.push_back({data[0],data[1].toDouble(),data[2].toDouble(),true,true,false});
kzw.known++;//已知点个数
}
// 读取未知点数量
line = in.readLine().trimmed();
int wzdn = line.toInt();
line = in.readLine().trimmed();
data =line.split(',');
for(int i = 0;i<wzdn;i++)
{
kzw.points.push_back({data[i],0,0,false,false,false});
}
//读取边长数量
line = in.readLine().trimmed();
int gcbn = line.toInt();
for(int i = 0;i<gcbn;i++)
{
line = in.readLine().trimmed();
data=line.split(',');
//错误检验
if(data.size()>3)
{
QMessageBox::critical(this,"Critical",tr("读取的边长观测数据格式有问题"));
}
int j,k;
for(j = 0;j<yzdn+wzdn;j++)
if(kzw.points[j].name==data[0])
break;
for(k=0;k<yzdn+wzdn;k++)
if(kzw.points[k].name==data[1])
break;
kzw.lengths.push_back({&kzw.points[j],&kzw.points[k],data[2].toDouble()});
}
//读取角度数量
line = in.readLine().trimmed();
int gcjn =line.toInt();
int g=0;//作用域的问题
for(int i=0;i<gcjn;i++)
{
line=in.readLine().trimmed();
data=line.split(',');
//错误检验
if(data.size()>3)
{
QMessageBox::critical(this,"Critical",tr("读取的角度观测数据格式有问题"));
}
int j,k;
for(j = 0;j<yzdn+wzdn;j++)
if(kzw.points[j].name==data[0])
break;
for(k = 0;k<yzdn+wzdn;k++)
if(kzw.points[k].name==data[1])
break;
if(data[2].toDouble()==0)
{
g=k;//记录定向边
kzw.sta.push_back({&kzw.points[j],&kzw.points[k],0});
kzw.station_sums++;//测站个数
}
else
kzw.iangles.push_back({&kzw.points[g],&kzw.points[j],&kzw.points[k],data[2].toDouble()});
kzw.cangles.push_back({&kzw.points[j],&kzw.points[k],data[2].toDouble()});
}
file.close();
qDebug() << "数据解析完成:";
qDebug() << "点数量:" << kzw.points.size();
qDebug() << "距离观测数量:" << kzw.lengths.size();
qDebug() << "角度观测数量:"<<kzw.iangles.size() << kzw.cangles.size();
return true;
}
void MainWindow::on_read_originaldata_Button_clicked()
{
// 步骤1: 获取文件路径
bool bOpen = getFilePath(mInputPath);
if (!bOpen) {
qDebug() << "未选择文件";
return;
}
ui->run_status_textEdit->append("获取文件\n");
int line_num ;//总行数
// 步骤2: 读取并显示原始文件内容
QFile file(mInputPath[0]);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream in(&file);
QString originalData = in.readAll();
line_num = originalData.split('\n').size();
ui->data_show_textEdit->setPlainText(originalData);
file.close();
} else {
qDebug() << "文件打开失败:" << mInputPath[0];
return;
}
ui->run_status_textEdit->append("读取文件\n");
// 步骤3: 调用解析函数,填充数据容器
bool parseSuccess = readSurveyData(mInputPath[0]);
if (parseSuccess) {
qDebug() << "数据解析成功";
} else {
qDebug() << "数据解析失败";
}
qDebug()<<kzw.known;
int line_sum = 4+kzw.known+1+kzw.cangles.size()+kzw.lengths.size();
qDebug()<<line_sum<<line_num;
if(line_num != line_sum)
{
QMessageBox::critical(this,"Critical",tr("读取的初始观测数据数量有问题"));
}
}
void MainWindow::on_budget_estimate_Button_clicked()
{
// 执行概算计算
kzw.gaisuan();
kzw.had_gs = true;//执行概算,已执行
ui->run_status_textEdit->append("进行概算\n");
// 输出概算结果
ui->data_show_textEdit->append("\n========================== 概算结果 ==========================");
ui->data_show_textEdit->append(QString("共计算 %1 个点").arg(kzw.points.size()));
// 表格头部
QString tableHeader = QString("%1\t%2\t%3\t %4\t%5\n")
.arg("点号").arg("概算后的X坐标").arg("概算后的Y坐标").arg("已知点").arg("参与概算");
ui->data_show_textEdit->append(tableHeader);
// 输出每个点的信息
for (const auto& point : kzw.points) {
QString row = QString("%1\t%2\t%3\t %4\t%5\n")
.arg(point.name)
.arg(point.X, 0, 'f', 4) // 保留4位小数
.arg(point.Y, 0, 'f', 4)
.arg(point.flag ? "是" : "否")
.arg(point.tag ? "是" : "否");
ui->data_show_textEdit->append(row);
}
ui->data_show_textEdit->append("\n========================== 概算完成 ==========================");
ui->run_status_textEdit->append("概算完成\n");
}
void MainWindow::on_indirect_adjustment_Button_clicked()
{
// 检查是否已执行概算
if (!kzw.had_gs) {
QMessageBox::warning(this, "警告", "请先执行概算计算!");
return;
}
kzw.pingcha();
kzw.had_pc = true;//执行平差,已执行
ui->run_status_textEdit->append("进行平差\n");
// 输出平差结果
ui->data_result_textEdit->
append("\n============================================================= 平差结果 =============================================================");
ui->data_result_textEdit->append(QString("共计算 %1 个点").arg(kzw.points.size()));
// 表格头部
QString tableHeader = QString("%1\t\t%2\t\t%3\t\t %4\t\t%5\n")
.arg("点号").arg("平差后的X坐标").arg("平差后的Y坐标").arg("已知点").arg("已平差");
ui->data_result_textEdit->append(tableHeader);
// 输出每个点的信息
for (const auto& point : kzw.points) {
QString row = QString("%1\t\t%2\t\t%3\t\t %4\t\t%5\n")
.arg(point.name)
.arg(point.X, 0, 'f', 4) // 保留4位小数
.arg(point.Y, 0, 'f', 4)
.arg(point.flag ? "是" : "否")
.arg(point.whe ? "是" : "否");
ui->data_result_textEdit->append(row);
}
ui->data_result_textEdit->
append("\n============================================================= 平差完成 =============================================================");
ui->data_result_textEdit->
append("\n================================================================================= "
"精度评定 "
"=================================================================================");
// 表格头部part2
QString tableHeader2 = QString("%1\t\t%2\t\t%3\t\t%4\t\t%5\t\t%6\t\t%7\n")
.arg("点号").arg("x点位误差").arg("y点位误差").arg("距离误差").arg("椭圆长半轴").arg("椭圆短半轴").arg("长半轴方位角");
ui->data_result_textEdit->append(tableHeader2);
// 输出每个点的信息
for (const auto& point : kzw.points) {
QString row = QString("%1\t\t%2\t\t%3\t\t%4\t\t%5\t\t%6\t\t%7\n")
.arg(point.name)
.arg(point.mx, 0, 'f', 6) // 保留6位小数
.arg(point.my, 0, 'f', 6)
.arg(point.mk, 0, 'f', 6)
.arg(point.E , 0, 'f', 6)
.arg(point.F , 0, 'f', 6)
.arg(point.Q , 0, 'f', 6);
ui->data_result_textEdit->append(row);
}
ui->run_status_textEdit->append("平差完成\n");
}
void MainWindow::on_jump_drawing_interface_Button_clicked()
{
// 检查是否已执行平差
if (!kzw.had_pc) {
QMessageBox::warning(this, "警告", "请先执行平差计算!");
return;
}
//信号与槽的对应链接
Draw_net_ellipse *newWindow=new Draw_net_ellipse;
connect(this,SIGNAL(send(KZW)),newWindow,SLOT(receive(KZW)));
emit send(kzw);
newWindow->show();
}
void MainWindow::on_quit_Button_clicked()
{
this->close();
}
void MainWindow::on_save_Button_clicked()
{
QString results;//平差结果
results=ui->data_result_textEdit->toPlainText();
QString outputFile = QFileDialog::getSaveFileName(this, tr("保存文件"), "", tr("Data Files (*.dat)"));
if (!outputFile.isEmpty())
{
QFile outFile(outputFile);
if (outFile.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream out(&outFile);
out << results; // 写入整理后的数据
outFile.close();
qDebug() << "文件已保存到" << outputFile;
}
else
{
qDebug() << "无法打开文件进行写入";
}
}
ui->run_status_textEdit->append("保存结果文件\n");
}
void MainWindow::on_check_pushButton_clicked()
{
QString dian_name;
dian_name = ui->pname_lineEdit->text();
ui->run_status_textEdit->append("要检测的点名是:\n");
ui->run_status_textEdit->append(dian_name+"\n");
bool name_exist = kzw.check_name(dian_name);
ui->data_result_textEdit->append("输出"+dian_name+"对应的B矩阵系数");
ui->data_result_textEdit->append(kzw.check_results);
if (name_exist)
{
ui->run_status_textEdit->append("已成功输出" + dian_name + "对应的B矩阵系数\n");
} else {
ui->run_status_textEdit->append("【错误】点名 \"" + dian_name + "\" 不存在,查询失败\n");
}
}
void MainWindow::on_clear_Button_clicked()
{
// 确认对话框
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "确认清除", "确定要清除所有数据和文本框内容吗?",
QMessageBox::Yes | QMessageBox::No);
if (reply != QMessageBox::Yes) return;
// 清空KZW类中的数据
kzw.points.clear();
kzw.lengths.clear();
kzw.iangles.clear();
kzw.cangles.clear();
kzw.sta.clear();
kzw.known = 0;//重置为零
kzw.station_sums = 0;//重置为零
kzw.had_gs = false; // 重置执行概算标志
kzw.had_pc = false; // 重置执行平差标志
// 清空数据显示文本框
ui->data_show_textEdit->clear();
// 清空数据结果文本框
ui->data_result_textEdit->clear();
// 清空运行状态文本框
ui->run_status_textEdit->clear();
// 清空点名输入框
ui->pname_lineEdit->clear();
}
3.main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
4.kzw.h
#ifndef KZW_H
#define KZW_H
#include<QString>
#include <QString>
#include <QVector>
#include <QList>
#include <Eigen/Dense>//引用eigen类
using namespace Eigen; //引用eigen类 操作步骤:属性 包含文件的路径
class KZW
{
public:
KZW();
struct Data {
QString line;//逐行读取数据时存储的容器
};
struct Point{
QString name;//点名
double X,Y;//坐标
bool flag;//是否为已知点
bool tag;//是否被概算
bool whe;//是否被平差
//未知点的点位误差和误差椭圆元素
double mx;//x点位误差
double my;//y点位误差
double mk;//距离误差
double E;//长半轴
double F;//短半轴
double Q;//长半径方位角
};
struct Length{
Point *start,*end;//测站点和照准点
double distance;//长度
};
struct include_Angle{
Point *start,*station,*end;//起测点和测站点和照准点
double angle;//夹角
};
struct ce_Angle{
Point *station,*end;//测站点和照准点
double angle;//方位角
};
struct station{
Point*station,*end;
double angle;
};
int station_sums = 0;//测站数
int known=0;//已知点个数
// 存储数据的容器
QVector<Point> points;
QVector<station> sta;
QVector<Length> lengths;
QVector<include_Angle> iangles;
QVector<ce_Angle> cangles;
double distance(double x1, double y1, double x2, double y2);//求距离
double azimuth(double dx, double dy);//求方位角
double dmsTorad(double dDms);//度分秒转弧度
double radTodms(double rad);//弧度转度分秒
void gaisuan();// 概算函数
double RHO = 206265.0;
//初始化矩阵
MatrixXd B;//误差方程系数阵
MatrixXd L;//误差方程常数阵
MatrixXd P;//权阵
MatrixXd Nbb;//法方程系数阵
MatrixXd fe;//法方程常数阵
MatrixXd XX;//坐标、角度改正数
MatrixXd V;//改正数
MatrixXd Qxx;//协因数阵
MatrixXd Min;
double m0;//单位权中误差
double min;//最小二乘准则,即vTpv
double pingcha();//平差函数
//绘图参数
int wgn = 10;//网格数
double s = 40;//误差椭圆比例 //已知点等边三角形的外接圆半径
bool draw_whe = false;//是否画误差椭圆
//输出检查
QString point_name ;//输入要检查的点名
bool check_name(const QString& pointName);
QString check_results;
//执行检查
bool had_gs = false;//保证先执行概算后平差
bool had_pc = false;//保证先执行平差在画图
};
5.kzw.cpp
#include "kzw.h"
#include <qmath.h>
#include<QDebug>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
KZW::KZW() {}
double KZW::distance(double x1, double y1, double x2, double y2)//输出距离
{
return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
}
double KZW::azimuth(double dx, double dy)//方位角输出弧度
{
if(dy>0)
return M_PI - M_PI/2 - atan(dx/dy);
else
return M_PI + M_PI/2 - atan(dx/dy);
}
double KZW::dmsTorad(double dms)
{
//dms拆分度分秒
int d,m,s;
d=int(dms);
m=int((dms-d)*100);
s=(dms-d-m/100.0)*10000;
return (d + m / 60.0 + s / 3600.0)*M_PI/180.0;
}
double KZW::radTodms(double rad)
{
double deg = rad*180/M_PI;
int du,min;
double second;
du = int(deg);
min = int((deg-du)*60);
second = ((deg-du)*60-min)*60;
return du+min/100.0+second/10000.0;
}
void KZW::gaisuan()
{
int unknownCount = 0;
// 统计未知点数量
for (const auto& point : points)
{
if (!point.tag)
{
unknownCount++;
}
}
while(unknownCount>0)
{
for (int i = 0; i < lengths.size(); ++i)//遍历测边
{
if(!lengths[i].end->tag&&lengths[i].start->tag)
{
for (int j = 0; j < iangles.size(); ++j)//用夹角去找
{
if (iangles[j].station->name == lengths[i].start->name)
{
if (iangles[j].end->name == lengths[i].end->name && iangles[j].start->tag)//左角的情况
{
double dx = iangles[j].start->X - iangles[j].station->X;
double dy = iangles[j].start->Y - iangles[j].station->Y;
double az = azimuth(dx, dy);
double t = dmsTorad(iangles[j].angle) + az ;
double x = lengths[i].start->X + lengths[i].distance * cos(t);
double y = lengths[i].start->Y + lengths[i].distance * sin(t);
lengths[i].end->X = x;
lengths[i].end->Y = y;
lengths[i].end->tag = true;
unknownCount--;
//qDebug() << "解算左角未知点:" << lengths[i].end->name;
break;
}
if(iangles[j].start->name == lengths[i].end->name && iangles[j].end->tag)//右角的情况
{
double dx = iangles[j].end->X - iangles[j].station->X;
double dy = iangles[j].end->Y - iangles[j].station->Y;
double az = azimuth(dx, dy);
double t = az - dmsTorad(iangles[j].angle);
double x = lengths[i].start->X + lengths[i].distance * cos(t);
double y = lengths[i].start->Y + lengths[i].distance * sin(t);
lengths[i].end->X = x;
lengths[i].end->Y = y;
lengths[i].end->tag = true;
unknownCount--;
//qDebug() << "解算右角未知点:" << lengths[i].end->name;
break;
}
}
}
}
}
}
}
double KZW::pingcha()
{
int unkP_num = 0 ;//未知点个数
for(int i = 0;i<points.size();i++)
{
if(!points[i].flag)
{
unkP_num++;
}
}
int tot_unk = 2*unkP_num;//X和Y
int tot_fx = cangles.size();
int tot_bc = lengths.size();
int row = tot_fx+tot_bc;
int col = tot_unk+station_sums;
B = MatrixXd::Zero(row,col);
qDebug()<<"B矩阵行数:"<<row<<Qt::endl<<"B矩阵列数:"<<col;
L = MatrixXd::Zero(row,1);
P = MatrixXd::Zero(row,row);//BTPB,可知
Nbb = MatrixXd::Zero(col, col); // 法方程系数阵(BTPB)^-1
fe = MatrixXd::Zero(col, 1); // 法方程常数阵(BTPL)
XX = MatrixXd::Zero(col, 1); // 未知数改正数(Nbb^-1*fe)
V = MatrixXd::Zero(row, 1); // 观测值改正数(BXX-L)
Qxx = MatrixXd::Zero(col, col); // 协因数阵(Nbb^-1)
double a_ij, b_ij; // 方向系数
double l_ij_fx, l_ij_bc; // 误差方程常数项
double T_ij, S_ij, S_ij0; // 方位角、实测边长、近似边长
double D_ij; // 近似距离
double Z_i0;
double L_ij;
int cal_num = 0;//迭代计算次数
//定权矩阵P
for(int i = 0;i<row;i++)
{
for(int j = 0;j<row;j++)
{
if (i != j)//将非对角部分转为零
{
P(i, j) = 0;
}
else if (i<tot_fx)//角度观测,等精度,定权为1 //先存角度再存边长
{
P(i,j) = 1;
}
else//边长观测,定权
{
P(i,j) = 1E5/lengths[i-tot_fx].distance;//单位要正确(将米转为毫米)
}
}
}
//平差
do
{
//填充B矩阵的方向观测
for(int k = 0;k<tot_fx;k++)
{
int s;
for(int i=0;i<sta.size();i++)
if(sta[i].station->name==cangles[k].station->name)
s=i;
if((cangles[k].station->flag) && (cangles[k].end->flag))//测站已知,照准点已知
{
B(k, tot_unk+s) = -1;
}
else if((!cangles[k].station->flag) && (cangles[k].end->flag))//测站未知,照准点已知
{
int l;
for(int i = points.size()-unkP_num;i<points.size();i++)
{
if(points[i].name==cangles[k].station->name)
{
l = i-known;
double dx = cangles[k].end->X - cangles[k].station->X ;
double dy = cangles[k].end->Y - cangles[k].station->Y ;
T_ij = azimuth(dx,dy);
double bc_c = cos(T_ij);
double bc_s = sin(T_ij);
B(k,2*l) = a_ij;//第l个未知点的X 在第k个测角观测中 方向系数
B(k,2*l+1) = b_ij;//第l个未知点的Y 在第k个测角观测中 方向系数
B(k,tot_unk+s) = -1;
}
}
}
else if((cangles[k].station->flag) && (!cangles[k].end->flag))//测站已知,照准点未知
{
int l;
for(int i = points.size()-unkP_num;i<points.size();i++)
{
if(points[i].name==cangles[k].end->name)
{
l = i-known;
double dx = cangles[k].end->X - cangles[k].station->X ;
double dy = cangles[k].end->Y - cangles[k].station->Y ;
T_ij = azimuth(dx,dy);
double bc_c = cos(T_ij);
double bc_s = sin(T_ij);
B(k,2*l) = - a_ij;
B(k,2*l+1) = - b_ij ;
B(k,tot_unk+s) = -1;
}
}
}
else if((!cangles[k].station->flag) && (!cangles[k].end->flag))//测站未知,照准点未知
{
int l,m;
for(int i = points.size()-unkP_num;i<points.size();i++)
{
if(points[i].name==cangles[k].station->name)
{
l = i-known;
for(int j = points.size()-unkP_num;j<points.size();j++)
{
if(points[j].name==cangles[k].end->name)
{
m = j-known;
double dx = cangles[k].end->X - cangles[k].station->X ;
double dy = cangles[k].end->Y - cangles[k].station->Y ;
T_ij = azimuth(dx,dy);
double bc_c = cos(T_ij);
double bc_s = sin(T_ij);
B(k,2*l) = a_ij;//第l个未知点的X 在第k个测角观测中 方向系数
B(k,2*l+1) = b_ij;//第l个未知点的Y 在第k个测角观测中 方向系数
B(k,+2*m) = - a_ij;//第m个未知点的X 在第k个测角观测中 方向系数
B(k,+2*m+1) = - b_ij;//第m个未知点的Y 在第k个测角观测中 方向系数
B(k,tot_unk+s) = -1;
}
}
}
}
}
}
//填充L矩阵的方向观测
int iStation = 1;//表示当前第几个测站
int iLocation = 0;//表示前一测站所在位置
for(int k = 0;k<tot_fx;k++)
{
if(cangles[k].station->name!=cangles[iLocation].station->name)//换站
{
iStation++; iLocation = k;
}
//L阵方向赋值
double dx = cangles[k].station->X - cangles[k].end->X;
double dy = cangles[k].station->Y - cangles[k].end->Y;
T_ij = azimuth(dx,dy);
double dx_z = cangles[iLocation].station->X - cangles[iLocation].end->X;
double dy_z = cangles[iLocation].station->Y - cangles[iLocation].end->Y;
Z_i0 = azimuth(dx_z,dy_z);
double l_ij_fx_0 = T_ij - Z_i0;
if(l_ij_fx_0<0)
{
l_ij_fx_0 = l_ij_fx_0 + 2*M_PI;
}
l_ij_fx = (l_ij_fx_0 -dmsTorad(cangles[k].angle))* 180 * 3600 / M_PI;//转为弧度秒的单位
L(k,0) = l_ij_fx;
}
//填充B矩阵的边长观测
for(int n = 0;n<tot_bc;n++)
{
if(!lengths[n].start->flag && lengths[n].end->flag)//测站点未知,照准点已知
{
int l;
for(int i = points.size()-unkP_num;i<points.size();i++)
{
if(points[i].name==lengths[n].start->name)
{
l = i-known;
double dx = lengths[n].end->X - lengths[n].start->X ;
double dy = lengths[n].end->Y - lengths[n].start->Y ;
T_ij = azimuth(dx,dy);
double bc_c = cos(T_ij);
double bc_s = sin(T_ij);
B(n+tot_fx ,2*l) = - bc_c;
B(n+tot_fx ,2*l+1) = - bc_s;
}
}
}
else if (lengths[n].start->flag && !lengths[n].end->flag)//测站点已知,照准点未知
{
int l;
for(int i = points.size()-unkP_num;i<points.size();i++)
{
if(points[i].name==lengths[n].end->name)
{
l = i-known;
double dx = lengths[n].end->X - lengths[n].start->X ;
double dy = lengths[n].end->Y - lengths[n].start->Y ;
T_ij = azimuth(dx,dy);
double bc_c = cos(T_ij);
double bc_s = sin(T_ij);
B(n+tot_fx ,2*l) = bc_c;
B(n+tot_fx ,2*l+1) = bc_s;
}
}
}
else if(!lengths[n].start->flag && !lengths[n].end->flag)//测站点未知,照准点未知
{
int l,m;
for(int i = points.size()-unkP_num;i<points.size();i++)
{
if(points[i].name==lengths[n].start->name)
{
l = i-known;
for(int j = points.size()-unkP_num;j<points.size();j++)
{
if(points[j].name==lengths[n].end->name)
{
m = j-known;
double dx = lengths[n].end->X - lengths[n].start->X ;
double dy = lengths[n].end->Y - lengths[n].start->Y ;
T_ij = azimuth(dx,dy);
double bc_c = cos(T_ij);
double bc_s = sin(T_ij);
B(n+tot_fx ,2*l) = - bc_c;
B(n+tot_fx ,2*l+1) = - bc_s;
B(n+tot_fx ,2*m) = bc_c;
B(n+tot_fx ,2*m+1) = bc_s;
}
}
}
}
}
}
//填充L矩阵的边长观测
for(int n = 0;n<tot_bc;n++)
{
S_ij0 = distance(lengths[n].start->X,lengths[n].start->Y,lengths[n].end->X,lengths[n].end->Y);
S_ij = lengths[n].distance;
l_ij_bc = (S_ij0 - S_ij)*100;//转为厘米的单位
L(n+tot_fx,0) = l_ij_bc;
}
//开始平差 //V = B * XX - L;
Nbb = B.transpose()*P*B;
fe = -1*B.transpose()*P*L;
XX = Nbb.inverse()*fe;
for(int i = known;i<points.size();i++)
{
if(!points[i].flag)
{
points[i].X = points[i].X+ XX(2*(i-known),0)/100.0;//迭代计算坐标
points[i].Y = points[i].Y+ XX(2*(i-known)+1,0)/100.0;
points[i].whe = true;
}
}
cal_num++;
}while(cal_num<4);
//精度评定
Qxx = Nbb.inverse();//未知数协因数阵
V = B * XX + L;
Min = V.transpose()*P*V;
min = Min(0,0);
m0 = sqrt(abs(min/(row - col)));
qDebug()<<"单位权中误差"<<m0;
for (int i = 0; i < points.size() ; i++)
{
if(i>=known)
{
double Qx = Qxx(2 * (i-known), 2 * (i-known));
double Qy = Qxx(2 * (i-known) + 1, 2 * (i-known) + 1);
double Qxy = Qxx(2 * (i-known), 2 * (i-known) + 1);
points[i].mx = m0 * sqrt(abs(Qx));
points[i].my = m0 * sqrt(abs(Qy));
points[i].mk = sqrt(points[i].mx*points[i].mx + points[i].my*points[i].my);
points[i].Q = atan(2 * Qxy / (Qx - Qy))/2;//长半径方位角
points[i].E = m0 * sqrt(Qx + Qxy * tan(points[i].Q));//长半轴
points[i].F = m0 * sqrt(Qx + Qxy * tan(points[i].Q + M_PI/2));//短半轴
}
else
{
points[i].mx = 0;
points[i].my = 0;
points[i].mk = 0;
points[i].Q = 0;//长半径方位角
points[i].E = 0;//长半轴
points[i].F = 0;//短半轴
}
}
//传输平差数据至绘图中
return 0;
}
bool KZW::check_name(const QString& pointName)
{
int tot_fx = cangles.size();
//输出第t个未知数对应的方向系数
//给未知点名,然后输出对应的方向系数
point_name = pointName;
int t = -1;
for(int i = 0;i<points.size();i++)
{
if(points[i].name == point_name)
{
t = i-1;//确定第t个未知点,就确定对应的列数
}
}
QString results2;
// 检查是否找到点名
if (t == -1)
{
// 未找到点名,显示警告对话框
QMessageBox::warning(nullptr, "查询错误", "无法查询该点,点名不存在!");
check_results = "查询失败:点名 \"" + pointName + "\" 不存在于数据中";
return false; // 未找到点名
}
results2.append(points[t+known-1].name + "\t第" + QString::number(t) + "个未知点的方向系数:\n");
for(int k = 0;k<cangles.size();k++)//遍历角度观测,找到对应的行数
{
if((!cangles[k].station->flag) && (cangles[k].end->flag))//测站未知,照准点已知
{
if(cangles[k].station->name == points[t+known-1].name)//第t个未知点作为测站点
{
results2.append("B(" + QString::number(k) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(k) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("a_ij:" + QString::number(B(k,2*(t-1))) + "\tb_ij" + QString::number(B(k,2*(t-1)+1)) + "\n");
}
}
else if((cangles[k].station->flag) && (!cangles[k].end->flag))//测站已知,照准点未知
{
if(cangles[k].end->name == points[t+known-1].name)//第t个未知点作为照准点
{
results2.append("B(" + QString::number(k) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(k) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("-a_ij:" + QString::number(B(k,2*(t-1))) + "\t-b_ij" + QString::number(B(k,2*(t-1)+1)) + "\n");
}
}
else if((!cangles[k].station->flag) && (!cangles[k].end->flag))//测站未知,照准点未知
{
if((cangles[k].station->name == points[t+known-1].name) && !cangles[k].end->flag)//第t个未知点作为测站点
{
results2.append("B(" + QString::number(k) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(k) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("a_ij:" + QString::number(B(k,2*(t-1))) + "\tb_ij" + QString::number(B(k,2*(t-1)+1)) + "\n");
}
else if((cangles[k].end->name == points[t+known-1].name) && (!cangles[k].start->flag))//第t个未知点作为照准点
{
results2.append("B(" + QString::number(k) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(k) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("-a_ij:" + QString::number(B(k,2*(t-1))) + "\t-b_ij" + QString::number(B(k,2*(t-1)+1)) + "\n");
}
}
}
results2.append(points[t+known-1].name + "\t第" + QString::number(t) + "个为未知点的边长系数:\n");
for(int l = 0;l<lengths.size();l++)//遍历边长观测,找到对应的行数
{
if(!lengths[l].start->flag && lengths[l].end->flag)//测站未知,观测站已知
{
if(lengths[l].start->name == points[t+known-1].name)
{
results2.append("B(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("-cos(T_ij):" + QString::number(B(l+tot_fx,2*(t-1))) + "\t-sin(T_ij):" + QString::number(B(l+tot_fx,2*(t-1)+1)) + "\n");
}
}
else if(lengths[l].start->flag && !lengths[l].end->flag)//测站已知,观测站未知
{
if(lengths[l].end->name == points[t+known-1].name)
{
results2.append("B(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("cos(T_ij):" + QString::number(B(l+tot_fx,2*(t-1))) + "\tsin(T_ij):" + QString::number(B(l+tot_fx,2*(t-1)+1)) + "\n");
}
}
else if(!lengths[l].start->flag && !lengths[l].end->flag)
{
if((lengths[l].start->name == points[t+known-1].name) && (!lengths[l].end->flag))
{
results2.append("B(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("-cos(T_ij):" + QString::number(B(l+tot_fx,2*(t-1))) + "\t-sin(T_ij):" + QString::number(B(l+tot_fx,2*(t-1)+1)) + "\n");
}
else if((lengths[l].end->name == points[t+known-1].name) && (!lengths[l].start->flag))
{
results2.append("B(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)) +
")\t\tB(" + QString::number(l+tot_fx) + "," + QString::number(2*(t-1)+1) + ")\n");
results2.append("cos(T_ij):" +QString::number(B(l+tot_fx,2*(t-1))) + "\tsin(T_ij):" + QString::number(B(l+tot_fx,2*(t-1)+1)) + "\n");
}
}
}
check_results = results2;
if (t == -1)
{
check_results = "查询失败:点名 \"" + pointName + "\" 不存在于数据中";
}
return true; // 找到点名
}
6.draw_net_ellipse.h
#ifndef DRAW_NET_ELLIPSE_H
#define DRAW_NET_ELLIPSE_H
#include <QWidget>
#include <QPainter>
#include "kzw.h"
namespace Ui {
class Draw_net_ellipse;
}
class Draw_net_ellipse : public QWidget
{
Q_OBJECT
public:
explicit Draw_net_ellipse(QWidget *parent = nullptr);
~Draw_net_ellipse();
bool isFlipped = false; // 翻转状态
void drawPointName(QPainter &painter, const QString &name, double x_q, double y_q); // 新增辅助函数
protected:
void paintEvent(QPaintEvent *event) override;
private slots:
void on_quit_Button_clicked();
void receive(KZW);//接受者
void on_wgn_spinBox_textChanged(const QString &arg1);
void on_ellipse_SpinBox_textChanged(const QString &arg1);
void on_checkBox_stateChanged(int arg1);
//答辩时老师让我临时添加的功能按钮
void on_fz_x_pushButton_clicked();
private:
QPen pen; // 画笔
KZW net;//实例化传过来的类
QBrush brush; // 画刷
Ui::Draw_net_ellipse *ui;
};
#endif // DRAW_NET_ELLIPSE_H
7.draw_net_ellipse.cpp
#include "draw_net_ellipse.h"
#include "ui_draw_net_ellipse.h"
#include <QPushButton>
#include <QPainter>
#include <QPoint>
Draw_net_ellipse::Draw_net_ellipse(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Draw_net_ellipse)
{
ui->setupUi(this);
}
void Draw_net_ellipse::receive(KZW a)
{
net=a;//接受传来的对象,net是画图的数据来源
}
void Draw_net_ellipse::paintEvent(QPaintEvent *)
{
QPainter painter(this);//画布
ui->wgn_spinBox->setValue(net.wgn);
ui->ellipse_SpinBox->setValue(net.s);
// 设置背景颜色,如果需要的话
painter.fillRect(this->rect(), Qt::white);
double xMax = net.points[0].X;
double xMin = net.points[0].X;
double yMax = net.points[0].Y;
double yMin = net.points[0].Y;//计算坐标的最值
for(int i = 0;i<net.points.size();i++)
{
xMin = qMin(xMin,net.points[i].X);
xMax = qMax(xMax,net.points[i].X);
yMin = qMin(yMin,net.points[i].Y);
yMax = qMax(yMax,net.points[i].Y);
}
// 计算 X 和 Y 坐标的范围
double xRange = xMax - xMin;
double yRange = yMax - yMin;
double maxRange = qMax(xRange, yRange);
//先画坐标系和网格
double w = width(),h = height();//w宽度,h高度 //屏幕
double Ox = 0.85*h,Oy = 0.15*w;//起点位置 //上下左右都要对应
int wgn;//网格数
wgn = net.wgn;//获取网格数
double deta_x,deta_y;//网格间隔 //屏幕画线的间隔
deta_x = 0.7*h/wgn;//0.8 -> 0.1 + 0.1
deta_y = 0.7*w/wgn;
double real_x,real_y;//坐标间隔 //屏幕显示的实际坐标划度
real_x = maxRange/wgn;
real_y = maxRange/wgn;
double scale = qMin(deta_x/real_x, deta_y/real_y);
QPen pen;
//绘制正交的网格线
for(int i = 0;i<=wgn;i++)//垂直线
{
pen.setColor(Qt::blue);
pen.setStyle(Qt::DashLine);
painter.setPen(pen);
if(i==0)//绘制坐标轴
{
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
//开始画坐标轴
painter.drawLine(Oy+i*real_y*scale,0.15*h,Oy+i*real_y*scale,0.85*h);//相同
//画箭头
painter.drawLine(0.15*w,0.15*h,0.15*w,0.15*h-30);
painter.drawLine(0.15*w,0.15*h-30,0.15*w-10,0.15*h-10);
painter.drawLine(0.15*w,0.15*h-30,0.15*w+10,0.15*h-10);
pen.setColor(Qt::black);
painter.setPen(pen);
painter.drawText(0.15*w,0.15*h-40,QString("X"));//X的标识
}
else//非X坐标轴的垂直线
{
pen.setStyle(Qt::DashLine);
painter.setPen(pen);
painter.drawLine(Oy+i*real_y*scale,0.15*h,Oy+i*real_y*scale,0.85*h);
}
pen.setColor(Qt::black);
painter.setPen(pen);
double actualY = yMin + i * real_y;
//QString label =QString :: number(static_cast<int>(yMin)+i*real_y);//垂直线对应的Y坐标值(真实的)
QString label =QString :: number(actualY, 'f', 2);//垂直线对应的Y坐标值(真实的)
painter.drawText(Oy+i*real_y*scale,0.85*h+20,label);//
}
for(int i = 0;i<=wgn;i++)//水平线
{
pen.setColor(Qt::blue);
pen.setStyle(Qt::DashLine);
painter.setPen(pen);
if(i==wgn)//绘制坐标轴
{
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
//开始画坐标轴
painter.drawLine(0.15*w,Ox-(wgn-i)*real_x*scale,0.85*w,Ox-(wgn-i)*real_x*scale);
//画箭头
painter.drawLine(0.85*w,0.85*h,0.85*w+30,0.85*h);
painter.drawLine(0.85*w+30,0.85*h,0.85*w+5,0.85*h+10);
painter.drawLine(0.85*w+30,0.85*h,0.85*w+5,0.85*h-10);
pen.setColor(Qt::black);
painter.setPen(pen);
painter.drawText(0.85*w+50,0.85*h,QString("Y"));//Y的标识
}
else//非Y坐标轴的水平线
{
pen.setStyle(Qt::DashLine);
painter.setPen(pen);
painter.drawLine(0.15*w,Ox-(wgn-i)*real_x*scale,0.85*w,Ox-(wgn-i)*real_x*scale);
}
pen.setColor(Qt::black);
painter.setPen(pen);
double actualX = xMax - i * real_x;
//QString label =QString :: number(static_cast<int>(xMax)-i*real_x);//水平线对应的X坐标值
QString label =QString :: number(actualX, 'f', 2);//水平线对应的X坐标值
painter.drawText(0.15*w-75,Ox-(wgn-i)*real_x*scale,label);
}
//画控制网
//绘制比例尺
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
QString scale_label = QString ("比例尺:1:%1").arg(real_x/deta_x);
painter.drawText(0.5*w,0.85*h+50,scale_label);
// 获取绘图区域的中心
QPointF center(width() / 2.0, height() / 2.0);
// 根据翻转状态应用变换
if (isFlipped) {
painter.translate(center);
painter.scale(1,- 1);
painter.translate(-center);
}
//遍历测角
for(int i = 0;i<net.cangles.size();i++)
{
pen.setColor(Qt::black);
painter.setPen(pen);
double x1,x2,y1,y2;//定义屏幕图上的坐标
x1 = net.cangles[i].station->X;//测站点//(实测)
y1 = net.cangles[i].station->Y;
x2 = net.cangles[i].end->X;//照准点
y2 = net.cangles[i].end->Y;
//更新为计算屏幕上的图片坐标
x2 = int(Ox-(x2-xMin)*scale);//从实测坐标变为屏幕坐标 //Ox-(x2-xMin)*x_scal
y2 = int(Oy+(y2-yMin)*scale);
x1 = int(Ox-(x1-xMin)*scale);
y1 = int(Oy+(y1-yMin)*scale);
//计算方位角,作为画双向线的上下偏移量
double az = net.azimuth(x2-x1,y2-y1);
double dis = sqrt(qPow(x2-x1,2)+qPow(y2-y1,2));
if(net.cangles[i].station->flag && net.cangles[i].end->flag)//已知边
{
pen.setColor(Qt::red);
painter.setPen(pen);
painter.drawLine(y1-2*cos(az),x1-2*sin(az),y2-2*cos(az),x2-2*sin(az));
painter.drawLine(y1+2*cos(az),x1+2*sin(az),y2+2*cos(az),x2+2*sin(az));
}
else//未知边绘制箭头
{
painter.drawLine(y1,x1,y2,x2);
painter.save();//保存此时的角度
painter.translate(y1,x1);//平移到测站点
painter.rotate(-net.radTodms(az));
//画箭头
painter.drawLine(0,dis,-5,dis-10);
painter.drawLine(0,dis,5,dis-10);
painter.restore();//恢复坐标轴
}
}
//输出点名和绘制未知点的误差椭圆,已知点画三角形
for(int i = 0;i<net.points.size();i++)
{
double x_q = net.points[i].X; // 先是实测表示
double y_q = net.points[i].Y;
x_q = int (Ox-(x_q-xMin)*scale);
y_q = int (Oy+(y_q-yMin)*scale);
QString name_label = QString("%1").arg(net.points[i].name);
drawPointName(painter, name_label, x_q, y_q); // 调用辅助函数绘制点名
//绘制未知点的误差椭圆和已知点的三角标识
if(net.points[i].flag)//已知点 //未平差
{
double x_q = net.points[i].X;//先是实测表示
double y_q = net.points[i].Y;
x_q = int (Ox-(x_q-xMin)*scale);
y_q = int (Oy+(y_q-yMin)*scale);
//画三角形(等边三角形)
pen.setColor((Qt::green));
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
int t =net.s/2;
if(t < 20)//net.s<40
{
t = 20;//保证已知点能显示
}
painter.drawLine(y_q,x_q-t,y_q-t*cos(M_PI/6),x_q+t*sin(M_PI/6));//三角形第一条边
painter.drawLine(y_q,x_q-t,y_q+t*cos(M_PI/6),x_q+t*sin(M_PI/6));//三角形第二条边
painter.drawLine(y_q-t*cos(M_PI/6),x_q+t*sin(M_PI/6),y_q+t*cos(M_PI/6),x_q+t*sin(M_PI/6));//三角形第三条边
}
else//未知点 //已平差
{
if(net.draw_whe == true)//打勾
{
double x_q = net.points[i].X;//先是实测表示
double y_q = net.points[i].Y;
x_q = int (Ox-(x_q-xMin)*scale);
y_q = int (Oy+(y_q-yMin)*scale);
//画误差椭圆
pen.setColor(Qt::red);
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
//类似于画箭头,要旋转坐标轴
painter.save();//保存此时坐标轴的角度
painter.translate(y_q,x_q);//平移到未知点
painter.rotate(-net.radTodms(net.points[i].Q));//将绘图时的轴旋转到误差椭圆的长半轴方位角上
//绘图
painter.drawLine(-net.points[i].E*net.s ,0,net.points[i].E*net.s,0);//绘制椭圆长轴
painter.drawLine(0,-net.points[i].F*net.s,0,net.points[i].F*net.s);//绘制椭圆短轴
painter.drawEllipse(-net.points[i].E*net.s,-net.points[i].F*net.s,2*net.points[i].E*net.s,2*net.points[i].F*net.s);//绘制误差椭圆
painter.restore();//恢复坐标轴
}
}
}
}
void Draw_net_ellipse::drawPointName(QPainter &painter, const QString &name, double x_q, double y_q)
{
if (isFlipped) {
// 获取绘图区域的中心
QPointF center(width() / 2.0, height() / 2.0);
painter.save(); // 保存当前的绘图状态
painter.translate(center);
painter.scale(1, -1);
painter.translate(-center);
pen.setColor(Qt::black);
painter.setPen(pen);
painter.drawText(y_q + 10, x_q - 10, name);
painter.restore(); // 恢复绘图状态
} else {
pen.setColor(Qt::black);
painter.setPen(pen);
painter.drawText(y_q + 10, x_q - 10, name);
}
}
Draw_net_ellipse::~Draw_net_ellipse()
{
delete ui;
}
void Draw_net_ellipse::on_quit_Button_clicked()
{
this->close();
}
void Draw_net_ellipse::on_wgn_spinBox_textChanged(const QString &arg1)
{
net.wgn = arg1.toInt();
this->update();
}
void Draw_net_ellipse::on_ellipse_SpinBox_textChanged(const QString &arg1)
{
net.s = arg1.toDouble();
//qDebug()<<"误差椭圆比例尺"<<net.s;
this->update();
}
void Draw_net_ellipse::on_checkBox_stateChanged(int arg1)
{
if(arg1 == Qt::Checked)
{
net.draw_whe = true;//打勾,画误差椭圆
}
else
{
net.draw_whe = false;//不打勾,隐藏误差椭圆
}
this->update();
}
//答辩时老师让我新添加的功能
void Draw_net_ellipse::on_fz_x_pushButton_clicked()
{
isFlipped = !isFlipped; // 切换翻转状态
this->update(); // 触发重绘
}
5.结果
设计的UI界面

平差的结果:



绘图的结果:

可显示误差椭圆:

可改变网格数和误差椭圆比例:

答辩添加的图像绕X轴翻转功能:


6.答辩心得
在答辩开始时,老师会检查运行代码,并给你一两个问题,让你现场增加功能,主要是图像是否为等比例尺、误差椭圆旋转、图像上下或者左右翻转等等,如果老师考得难就是会让你把绘图的UI界面也写到平差的主窗口中。
简单来说,对代码的了解程度决定了你答辩时的情况。
主要会考察平差和概算的细节,以及会现场让参加答辩的人改动对B矩阵的填充方式和或者让人输出某个未知点的B矩阵系数,并且询问你认为自己的代码或者界面设计的闪光点。
本人设计的“检查”功能便是自己的一个闪光点,可以根据输入点名查询在B矩阵中对应的方向系数和边长系数。
7.结语
博主在答辩时拿到A(优)的成绩,在修改代码的时候浪费许多时间,博主的原始图像并不是等比例尺而是被拉伸过的,我在答辩时被要求现场改成等比例尺并且增加绕X轴翻转的功能,这里提醒大家,老师让你修改代码,尽量还是自己修改,博主就是在修改代码时偷懒了,用AI去做,结果最后还得是靠自己把功能改出来。
对于使用QT运行环境学习的朋友或者学弟学妹们,希望这篇文章能对大家有启发,但是还是提醒大家,自己的代码自己写,如果抱有侥幸心理的话,在答辩时肯定会露馅。
最后,博主的代码也许不是最有效率的,界面也许不是设计得最美观的,心得也许不是最详细的,但是博主也希望大家生活如意,诸事顺心。
190

被折叠的 条评论
为什么被折叠?



