导线网间接平差程序设计————QT(遥感程序设计)

这是湖南某高校的一次遥感程序设计实践,共十天时间,博主在经历了八天的实习后进行答辩,学长学姐都是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运行环境学习的朋友或者学弟学妹们,希望这篇文章能对大家有启发,但是还是提醒大家,自己的代码自己写,如果抱有侥幸心理的话,在答辩时肯定会露馅。

最后,博主的代码也许不是最有效率的,界面也许不是设计得最美观的,心得也许不是最详细的,但是博主也希望大家生活如意,诸事顺心。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值