本程序提供了导线网平差所用到的全部C++代码,在MFC窗口内调试后可直接运行。尝试
原始数据(格式)
界面设计
点击画图按钮后弹出的对话框
类的设计
Data类:存放点号、坐标、未知点误差椭圆元素
Gangle类:存储起测站、照准点、角度观测值
Length类:存储起测站、照准点、边长观测值
support类:存放各种函数和矩阵
Eigen类:用于矩阵运算
源代码
<Data.h>
#pragma once
#include <afxext.h>
#include <math.h>
#include <locale.h>
class Data
{
public:
Data();
~Data();
bool whether;//判断点坐标是否已存在
CString dianhao;//点号
double X;
double Y;//坐标
//未知点的点位误差和误差椭圆元素
double mx;//x点位误差
double my;//y点位误差
double mk;//距离误差
double E;//长半轴
double F;//短半轴
double Q;//长半径方位角
};
<Data.cpp>
#include "pch.h"
#include "Data.h"
Data::Data()
{
}
Data::~Data()
{
}
<Gangle.h>
#pragma once
#include "Data.h"
class Gangle
{
public:
Gangle();
~Gangle();
Data* Qizhan;//起测站
Data* Zhaozhan;//照准点
double GCangle;//角度观测值
};
<Gangle.cpp>
#include "pch.h"
#include "Gangle.h"
Gangle::Gangle()
{
}
Gangle::~Gangle()
{
}
<Length.h>
#pragma once
#include "Data.h"
class Length
{
public:
Length();
~Length();
Data* Qdian;//起点号
Data* Zdian;//终点号
double Glength;//边长观测值
};
<Length.cpp>
<Length.cpp>
#include "pch.h"
#include "Length.h"
Length::Length()
{
}
Length::~Length()
{
}
<support.h>
#pragma once
#include<iostream>
#include"Data.h"
#include"Length.h"
#include"Gangle.h"
#include<gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
#include <Eigen/Dense>//引用eigen类
using namespace Eigen; //引用eigen类 操作步骤:属性 包含文件的路径
class support
{
private:
Data *KZD;//定义已知点指针
Data *WZD;//定义未知点指针
juli *GCB;//定义观测边指针
Gangle *GCJ;//定义观测角
int KZDsums;//控制点个数
int unkownsunms;//未知点个数
int diansums;//总点数
int Glengthsums;//观测边数目
int Ganglesums;//观测角度数目
int CZsums = 0;//测站数
public:
support();
~support();
bool panduan = 0;//判断是否读入数据
CString cunchu;//存储数据
CString cunchu1;//存储概算数据
CString cunchu2;//存储平差数据
CString cunchu3;
double tak;//方向观测值
double tab;//方向观测值
double A_;//A'
double A;
double Tab;
double Tak;
double T_ak;//T_ak=Tab+a
//初始化矩阵
MatrixXd B;//系数阵
MatrixXd L;//常数阵
MatrixXd P;//权阵
MatrixXd Nbb;
MatrixXd fe;
MatrixXd XX;//坐标、角度改正数
MatrixXd V;//改正数
MatrixXd Qxx;//协因数阵
MatrixXd Min;
double m0;//单位权中误差
double min;//最小二乘准则
double read();//读入数据函数
double gaisuan();//概算函数
double pingcha();//平差函数CMatrix& B, CMatrix& L
void huitu(CDC * pDc, CRect rect, double karfa);//绘图函数
double Maxmin1x(Data *KZD, int KZDsums, int tag);
double Maxmin1y(Data *KZD, int KZDsums, int tag);
double Maxmin2x(Data *WZD, int unkownsunms, int tag);//确定X、Y最值
double Maxmin2y(Data *WZD, int unkownsunms, int tag);
void huiKZD(CDC* pDC, double x, double y, double length, double a);//画出控制点位置
double dms2rad(double dDms);
double rad2dms(double dDeg);
double fangweijiao(double x1, double y1, double x2, double y2);//求方位角
CString * SplitString(CString str, char split, int& iSubStrs);//字符串分割函数
Data* zhuanhuan(CString dianhao);//返回点对应站储存的地址,否则读入数据时CString变量无法转换为指针变量
};
<support.cpp>
#include "pch.h"
#include "support.h"
#include <Eigen/Dense>//引用eigen类
support::support()
{
}
support::~support()
{
}
const double pi = 4.0*atan(1.0);//定义pi
double p_ = 206265;//定义p''
//度分秒转弧度函数
double hanshu::dms2rad(double dDms)
{
int iDegree, iMin;
double dSec;//存放度分秒
double dDeg;
iDegree = int(dDms);
iMin = int((dDms - iDegree) * 100);
dSec = ((dDms - iDegree) * 100 - iMin) * 100;
dDeg = iDegree + double(iMin) / 60 + dSec / 3600;
dDeg = dDeg / 180.0 * pi;
return dDeg;
}
double support::rad2dms(double dDeg)
{
int iDegree, iMin;
double dSec;//存放度分秒
double dDms;
dDeg = dDeg / pi * 180;
iDegree = int(dDeg);
iMin = int((dDeg - iDegree) * 60);
dSec = ((dDeg - iDegree) * 60 - iMin) * 60;
dDms = iDegree + double(iMin) / 100 + dSec / 10000;
return dDms;
}
//字符串分割函数
CString * support::SplitString(CString str, char split, int& iSubStrs)
{
int iPos = 0; //分割符位置
int iNums = 0; //分割符的总数
CString strTemp = str;
CString strRight;
//先计算子字符串的数量
while (iPos != -1)
{
iPos = strTemp.Find(split);
if (iPos == -1)
{
break;
}
strRight = strTemp.Mid(iPos + 1, str.GetLength());
strTemp = strRight;
iNums++;
}
if (iNums == 0) //没有找到分割符
{
//子字符串数就是字符串本身
iSubStrs = 1;
return NULL;
}
//子字符串数组
iSubStrs = iNums + 1; //子串的数量 = 分割符数量 + 1
CString* pStrSplit;
pStrSplit = new CString[iSubStrs];
strTemp = str;
CString strLeft;
for (int i = 0; i < iNums; i++)
{
iPos = strTemp.Find(split);
//左子串
strLeft = strTemp.Left(iPos);
//右子串
strRight = strTemp.Mid(iPos + 1, strTemp.GetLength());
strTemp = strRight;
pStrSplit[i] = strLeft;
}
pStrSplit[iNums] = strTemp;
return pStrSplit;
}
//方位角函数,输出形式为弧度
double support::fangweijiao(double x1, double y1, double x2, double y2)
{
double dTmp;//设置临时变量用于返回方位角弧度
double x0 = x2 - x1;
double y0 = y2 - y1;
if (x0 > 0)
{
if (y0 > 0)
{
dTmp = atan(y0 / x0);//第一象限
}
else if (y0 < 0)
{
dTmp = atan(y0 / x0) + 2 * pi;//第四象限
}
else
dTmp = 0;//在x轴正半轴上
}
else if (x0 < 0)
{
if (y0 > 0)
{
dTmp = atan(y0 / x0) + pi;//第二象限
}
else if (y0 < 0)
{
dTmp = atan(y0 / x0) + pi;//第三象限
}
else
dTmp = pi;//在x轴负半轴上
}
else
{
if (y0 > 0)
dTmp = pi / 2;//Y轴正半轴
else
dTmp = 3 * pi / 2;//Y轴负半轴
}
return dTmp;
}
//CString变量转换为指针变量转换函数(将起点、终点、测站、照准点绑定坐标和点号用)
Data* support::zhuanhuan(CString dianhao)
{
Data* Temp;//创建一个Data*指针型临时变量
Temp = nullptr;//初始化指针
for (int i = 0; i < KZDsums; i++)
{
if (dianhao == KZD[i].dianhao)
{
Temp = &KZD[i];
}
else
{
for (int j = 0; j < unkownsunms; j++)
{
if (dianhao == WZD[j].dianhao)
{
Temp = &WZD[j];
}
}
}
}
return Temp;//返回指针变量
}
//读取数据并输出函数
double support::read()
{
CFileDialog dlgFile(TRUE, _T("dat/txt"), NULL, OFN_EXPLORER, _T("(文本文件)|*.dat|(文本文件)|*.txt"));//打开文件对话框
if (dlgFile.DoModal() == IDCANCEL) return 0;//如果选择取消按钮则退出
CString strFileName = dlgFile.GetPathName();//获取选择文件的名称
setlocale(LC_ALL, "");//对程序进行地域设置
CStdioFile sf;//创建文件对象
if (!sf.Open(strFileName, CFile::modeRead)) return 0;//打开strName文件路径中的内容
CString strLine;
BOOL bEOF = sf.ReadString(strLine);//读取第一行
cunchu += strLine;
cunchu += _T("\r\n");
if (!bEOF)//如果读取失败,则数据格式有问题,退出
{
AfxMessageBox(_T("数据有误!"));
return 0;
}
//读取控制点
KZDsums = _ttoi(strLine);
KZD = new Data[KZDsums];
int i = 0;
int n = 0;
while (i < KZDsums)
{
bEOF = sf.ReadString(strLine);
CString *dushu = SplitString(strLine, ',', n);
KZD[i].dianhao = dushu[0];
KZD[i].X = _tstof(dushu[1]);
KZD[i].Y = _tstof(dushu[2]);
KZD[i].whether = 1;//已知点坐标已知
cunchu += strLine;
cunchu += _T("\r\n");
i++;
}
bEOF = sf.ReadString(strLine);
cunchu += strLine;
cunchu += _T("\r\n");
if (!bEOF)//如果读取失败,则数据格式有问题,退出
{
AfxMessageBox(_T("数据有误!"));
return 0;
}
//读取未知点
unkownsunms = _ttoi(strLine);
WZD = new Data[unkownsunms];
bEOF = sf.ReadString(strLine);
cunchu += strLine;
cunchu += _T("\r\n");
i = 0;
while (i < unkownsunms)
{
CString *dianshu = SplitString(strLine, ',', n);
WZD[i].dianhao = dianshu[i];
WZD[i].whether = 0;//未知点坐标未知
i++;
}
//读取观测边长
bEOF = sf.ReadString(strLine);
cunchu += strLine;
cunchu += _T("\r\n");
if (!bEOF)//如果读取失败,则数据格式有问题,退出
{
AfxMessageBox(_T("数据有误!"));
return 0;
}
Glengthsums = _ttoi(strLine);
GCB = new juli[Glengthsums];
i = 0;
while (i < Glengthsums)
{
bEOF = sf.ReadString(strLine);
CString *bianshu = SplitString(strLine, ',', n);
GCB[i].Qdian = zhuanhuan(bianshu[0]);
GCB[i].Zdian = zhuanhuan(bianshu[1]);
GCB[i].Glength = _tstof(bianshu[2]);
cunchu += strLine;
cunchu += _T("\r\n");
i++;
}
//读取角度
bEOF = sf.ReadString(strLine);
if (!bEOF)//如果读取失败,则数据格式有问题,退出
{
AfxMessageBox(_T("数据有误!"));
return 0;
}
Ganglesums = _ttoi(strLine);
GCJ = new Gangle[Ganglesums];
cunchu += strLine;
cunchu += _T("\r\n");
i = 0;
while (i < Ganglesums)
{
bEOF = sf.ReadString(strLine);
CString *jiaoshu = SplitString(strLine, ',', n);
GCJ[i].Qizhan = zhuanhuan(jiaoshu[0]);
GCJ[i].Zhaozhan = zhuanhuan(jiaoshu[1]);
GCJ[i].GCangle = _tstof(jiaoshu[2]);
cunchu += strLine;
cunchu += _T("\r\n");
i++;
}
panduan = 1;//证明以读入数据
diansums = KZDsums + unkownsunms;
CZsums = 0;//计算测站数
for (int i = 0; i < Ganglesums; i++)
{
if (GCJ[i].GCangle == 0)
{
CZsums++;
}
}
sf.Close();
return 0;
}
bool panduan1 = 0;//用于判定是否概算
//概算函数并输出结果
double support::gaisuan()
{
if (panduan == 0)
{
AfxMessageBox(_T("请输入数据"));
}
else
{
AfxMessageBox(_T("进行概算"));
/*********计算近似坐标********/
int yisuan = 0;//记录已算点数据
while (yisuan < unkownsunms)//所有位置点坐标近似值算出后结束循环
{
for (int i = 0; i < Ganglesums; i++)
{
if (GCJ[i].Qizhan->whether == 1 && GCJ[i].Zhaozhan->whether == 1)//如果起测站和一个照准点已知
{
for (int j = 0; j < Ganglesums; j++)
{
if (GCJ[j].Qizhan == GCJ[i].Qizhan &&GCJ[j].Zhaozhan->whether == 0)//起测站和上面一样,但照准点未知
{//此时可以算Tab、A_、A
A_ = dms2rad(GCJ[j].GCangle) - dms2rad(GCJ[i].GCangle);
if (A_ < 0)
{
A = A_ + 2 * pi;
}
else
{
A = A_;
}
Tab = fangweijiao(GCJ[i].Qizhan->X, GCJ[i].Qizhan->Y, GCJ[i].Zhaozhan->X, GCJ[i].Zhaozhan->Y);
T_ak = Tab + A;//计算T'ak
if (T_ak > 2 * pi)
{
Tak = T_ak - 2 * pi;
}
else
{
Tak = T_ak;
}
//下面找寻d
for (int k = 0; k < Glengthsums; k++)
{
if ((GCJ[j].Qizhan->dianhao == GCB[k].Qdian->dianhao && GCJ[j].Zhaozhan->dianhao == GCB[k].Zdian->dianhao)
|| (GCJ[j].Qizhan->dianhao == GCB[k].Zdian->dianhao && GCJ[j].Zhaozhan->dianhao == GCB[k].Qdian->dianhao))
//如果起测站和位置点在观测边长中有对应的边长
{
double length = 0;
length = GCB[k].Glength;
GCJ[j].Zhaozhan->X = GCJ[j].Qizhan->X + length * cos(Tak);
GCJ[j].Zhaozhan->Y = GCJ[j].Qizhan->Y + length * sin(Tak);
GCJ[j].Zhaozhan->whether = 1;
yisuan = yisuan + 1;
}
}
}
}
}
}//对应while
//while循环结束后,此时所有点的近似坐标已知
//下面对近似坐标进行输出
}
}//对应else
panduan1 = 1;
CString tem;//此部分用于输出概算结果
cunchu1 += "已知点坐标:\r\n";
for (int i = 0; i < KZDsums; i++)
{
tem.Format(_T("%s\t%.4f\t%.4f\r\n"), KZD[i].dianhao, KZD[i].X, KZD[i].Y);
cunchu1 += tem;
}//输出已知点
cunchu1 += "未知点概算后坐标:\r\n";
for (int i = 0; i < unkownsunms; i++)
{
tem.Format(_T("%s\t%.4f\t%.4f\r\n"), WZD[i].dianhao, WZD[i].X, WZD[i].Y);
cunchu1 += tem;
}//输出未知点近似坐标
return 0;
}
bool panduan2 = 0;//用于判断是否进行平差
double support::pingcha()
{
B.resize(Glengthsums + Ganglesums, 2 * unkownsunms + CZsums);//系数阵
L.resize(Glengthsums + Ganglesums, 1);//常数项
B.setZero();
double a1, b1, a2, b2;//改正系数
int DDsums = 0;//迭代次数
if (panduan == 0)
{
AfxMessageBox(_T("请输入数据"));
}
else
{
if (panduan1 == 0)
{
AfxMessageBox(_T("请先进行概算"));
}
else//开始平差
{
//方向观测误差方程式
AfxMessageBox(_T("开始平差"));
double T0, Z0, L0, l1;
double dx, dy, ds;//方向坐标差
P.resize(Glengthsums + Ganglesums, Glengthsums + Ganglesums);//权矩阵
//求权矩阵
for (int i = 0; i < (Glengthsums + Ganglesums); i++)
{
for (int j = 0; j < (Glengthsums + Ganglesums); j++)
{
if (i != j)//将非对角部分转为零
{
P(i, j) = 0;
}
else if (i < Ganglesums)//由于是等精度观测,故将方向观测值的权定为1
{
P(i, j) = 1;
}
else//下面为边长观测的权
{
P(i, j) = 100 / GCB[i - Ganglesums].Glength;
}
}
}
do {
int iStation = 1;//表示当前第几个测站
int iLocation = 0;//表示前一测站所在位置
for (int i = 0; i < Ganglesums; i++)
{
if (GCJ[i].Qizhan->dianhao != GCJ[iLocation].Qizhan->dianhao)//如果换站
{
//右为角度坐标:GCJ[i].Qizhan、GCJ[i].Zhaozhan、GCJ[i].GCangle
//右为边长坐标:GCB[i].Qdian、GCB[i].Zdian、GCB[i].Glength
iStation++; iLocation = i;
}
B(i, 2 * unkownsunms + iStation - 1) = -1;//方向改正数
//B矩阵方向赋值
dx = GCJ[i].Zhaozhan->X - GCJ[i].Qizhan->X;
dy = GCJ[i].Zhaozhan->Y - GCJ[i].Qizhan->Y;
ds = sqrt(dx*dx + dy * dy);
a1 = p_ * dy / (ds*ds * 1000.0);//由于ds单位为毫米,故需乘以1000
b1 = -p_ * dx / (ds*ds * 1000.0);
for (int j = 0; j < unkownsunms; j++)
{
if (GCJ[i].Qizhan->dianhao == WZD[j].dianhao)//如果观测值测站是第j个未知点
{
B(i, 2 * j) = a1; B(i, 2 * j + 1) = b1;
}
if (GCJ[i].Zhaozhan->dianhao == WZD[j].dianhao)//如果观测值测站是第j个未知点
{
B(i, 2 * j) = -a1; B(i, 2 * j + 1) = -b1;
}
}
//L阵方向赋值
T0 = fangweijiao(GCJ[i].Qizhan->X, GCJ[i].Qizhan->Y, GCJ[i].Zhaozhan->X, GCJ[i].Zhaozhan->Y);
Z0 = fangweijiao(GCJ[iLocation].Qizhan->X, GCJ[iLocation].Qizhan->Y, GCJ[iLocation].Zhaozhan->X, GCJ[iLocation].Zhaozhan->Y);
L0 = T0 - Z0;
if (L0 < 0)
{
L0 = L0 + 2 * pi;
}
l1 = (dms2rad(GCJ[i].GCangle) - L0) * 180 * 3600 / pi;//转换为秒
L(i, 0) = l1;
}
//B矩阵距离赋值
double dX0, dY0, dS;//边长坐标差
for (int i = 0; i < Glengthsums; i++)
{
double l2;//距离系数阵
dX0 = GCB[i].Zdian->X - GCB[i].Qdian->X;
dY0 = GCB[i].Zdian->Y - GCB[i].Qdian->Y;
dS = sqrt(dX0*dX0 + dY0 * dY0);
a2 = dX0 / dS;
b2 = dY0 / dS;
for (int j = 0; j < unkownsunms; j++)
{
if (GCB[i].Qdian->dianhao == WZD[j].dianhao)//如果观测值测站是第j个未知点
{
B(i + Ganglesums, 2 * j) = -a2; B(i + Ganglesums, 2 * j + 1) = -b2;
}
if (GCB[i].Zdian->dianhao == WZD[j].dianhao)//如果观测值照准点是第j个未知点
{
B(i + Ganglesums, 2 * j) = a2; B(i + Ganglesums, 2 * j + 1) = b2;
}
}
//L阵距离部分赋值
l2 = (GCB[i].Glength - dS)*1000.0;//换算成毫米
L(i + Ganglesums, 0) = l2;
}
//开始平差
Nbb.resize(2 * unkownsunms + CZsums, 2 * unkownsunms + CZsums);//Nbb=B'PB
fe.resize(2 * unkownsunms + CZsums, 1);//fe=B'PL
XX.resize(2 * unkownsunms + CZsums, 1);//XX=Nbb^-1*fe
Nbb = B.transpose()*P*B;
fe = B.transpose()*P*L;
XX = Nbb.inverse()*fe;
V.resize(Glengthsums + Ganglesums, 1);//初始化V阵
V = B * XX - L;
for (int i = 0; i < unkownsunms; i++)
{
WZD[i].X = WZD[i].X + XX(2 * i, 0) / 1000;//计算坐标
WZD[i].Y = WZD[i].Y + XX(2 * i + 1, 0) / 1000;
}
DDsums++;
} while (DDsums < 4);
}//平差结束
//精度评定
Qxx.resize(2 * unkownsunms + CZsums, 2 * unkownsunms + CZsums);
Qxx = Nbb.inverse();//未知数协因数阵
Min = V.transpose()*P*V;
min = Min(0, 0);
m0 = sqrt(abs(min / (Glengthsums + Ganglesums - 2 * unkownsunms - CZsums)));//单位权中误差
for (int i = 0; i < unkownsunms; i++)//进行循环计算每个位置点的点位误差和误差椭圆元素
{
double Qx = Qxx(2 * i, 2 * i);
double Qy = Qxx(2 * i + 1, 2 * i + 1);
double Qxy = Qxx(2 * i, 2 * i + 1);
WZD[i].mx = m0 * sqrt(abs(Qx));
WZD[i].my = m0 * sqrt(abs(Qy));
WZD[i].mk = sqrt(WZD[i].mx*WZD[i].mx + WZD[i].my * WZD[i].my);
WZD[i].Q = atan(2 * Qxy / (Qx - Qy)) / 2;//长半径方位角
WZD[i].E = m0 * sqrt(Qx + Qxy * tan(WZD[i].Q));//长半轴
WZD[i].F = m0 * sqrt(Qx + Qxy * tan(WZD[i].Q + pi / 2));//短半轴
}
//对平差结果进行输出
CString com;//输出平差结果
//com.Format(_T("%s\t%s%f\r\n"), _T("最终所有点的坐标:"));
cunchu2 += "已知点坐标:\r\n";
for (int i = 0; i < KZDsums; i++)
{
com.Format(_T("%s\t%.4f\t%.4f\r\n"), KZD[i].dianhao, KZD[i].X, KZD[i].Y);
cunchu2 += com;
}//输出已知点
cunchu2 += "未知点平差后坐标:\r\n";
for (int i = 0; i < unkownsunms; i++)
{
com.Format(_T("%s\t%.4f\t%.4f\r\n"), WZD[i].dianhao, WZD[i].X, WZD[i].Y);
cunchu2 += com;
}//输出未知点近似坐标
com.Format(_T("%s%d\r\n"), _T("迭代次数:"), DDsums);
cunchu2 += com;
com.Format(_T("%s\t%s%f\r\n"), _T("单位中误差(mm):"), _T("±"), m0);
cunchu2 += com;
cunchu2 += "距离观测成果:\r\n";
cunchu2 += "测站\t照准\t距离观测值(m)\t改正数(m)\t平差后值(m)\t方位角(dms)\r\n";
for (int i = 0; i < Glengthsums; i++)
{
com.Format(_T("%s\t%s\t%.6f %.6f %.6f %.6f\r\n"),
GCB[i].Qdian->dianhao,
GCB[i].Zdian->dianhao,
GCB[i].Glength,
V(i + Ganglesums, 0) / 1000,
GCB[i].Glength + V(i + Ganglesums, 0) / 1000,
rad2dms(fangweijiao(GCB[i].Qdian->X, GCB[i].Qdian->Y, GCB[i].Zdian->X, GCB[i].Zdian->Y)));
cunchu2 += com;
}
cunchu2 += "方向观测成果:\r\n";
cunchu2 += "测站 找准 观测方向值(dms)\t改正数(s)\t改正后的值\r\n";
for (int i = 0; i < Ganglesums; i++)
{
com.Format(_T("%s\t%s %.4f %.4f %.4f\r\n"),
GCJ[i].Qizhan->dianhao,
GCJ[i].Zhaozhan->dianhao,
GCJ[i].GCangle,
V(i, 0) / 1000,
GCJ[i].GCangle + V(i, 0) / 1000);
cunchu2 += com;
}
}
panduan2 = 1;//证明已完成平差
return 0;
}
//求控制点x最值
double support::Maxmin1x(Data *KZD, int KZDsums, int tag)
{
double Temp = KZD[0].X;
if (tag == 2)//返回最大值
{
for (int i = 0; i < KZDsums - 1; i++)
{
if (KZD[i + 1].X > Temp)
{
Temp = KZD[i + 1].X;
}
}
}
else if (tag == 1)
{
for (int i = 0; i < KZDsums - 1; i++)
{
if (KZD[i + 1].X < Temp)
{
Temp = KZD[i + 1].X;
}
}
}
return Temp;
}
//求控制点y最值
double support::Maxmin1y(Data *KZD, int KZDsums, int tag)
{
double Temp = KZD[0].Y;
if (tag == 2)//返回最大值
{
for (int i = 0; i < KZDsums - 1; i++)
{
if (KZD[i + 1].Y > Temp)
{
Temp = KZD[i + 1].Y;
}
}
}
else if (tag == 1)
{
for (int i = 0; i < KZDsums - 1; i++)
{
if (KZD[i + 1].Y < Temp)
{
Temp = KZD[i + 1].Y;
}
}
}
return Temp;
}
//求未知点x最值
double support::Maxmin2x(Data *WZD, int unkownsunms, int tag)
{
double Temp = WZD[0].X;
if (tag == 2)//返回最大值
{
for (int i = 0; i < unkownsunms - 1; i++)
{
if (WZD[i + 1].X > Temp)
{
Temp = WZD[i + 1].X;
}
}
}
else if (tag == 1)
{
for (int i = 0; i < unkownsunms - 1; i++)
{
if (WZD[i + 1].X < Temp)
{
Temp = WZD[i + 1].X;
}
}
}
return Temp;
}
//求未知点y最值
double support::Maxmin2y(Data *WZD, int unkownsunms, int tag)
{
double Temp = WZD[0].Y;
if (tag == 2)//返回最大值
{
for (int i = 0; i < unkownsunms - 1; i++)
{
if (WZD[i + 1].Y > Temp)
{
Temp = WZD[i + 1].Y;
}
}
}
else if (tag == 1)
{
for (int i = 0; i < unkownsunms - 1; i++)
{
if (WZD[i + 1].Y < Temp)
{
Temp = WZD[i + 1].Y;
}
}
}
return Temp;
}
//画控制点位置
void support::huiKZD(CDC* pDC, double x, double y, double length, double a)//y轴向下
{
double l = length * 0.5*a;
CPen pen;
pen.CreatePen(PS_SOLID, 1.8, RGB(0, 255, 0));//实现画笔
CPen *pOldPen;
pOldPen = pDC->SelectObject(&pen);
pDC->MoveTo(x - l, y + l / sqrt(3));
pDC->LineTo(x + l, y + l / sqrt(3));
pDC->LineTo(x, y - 2 * sqrt(3)*l / 3);
pDC->LineTo(x - l, y + l / sqrt(3));
}
void support::huitu(CDC * pDC, CRect rect, double karfa)
{
int X01 = 0;//屏幕的左上角x
int Y01 = 0;//屏幕的左上角y
int X02 = rect.Width()-300;//屏幕的右下角x
int Y02 = rect.Height() - 175; //屏幕的右下角y
if (panduan == 0)
{
AfxMessageBox(_T("请输入数据"));
}
else if (panduan1 == 0)
{
AfxMessageBox(_T("请先进行概算"));
}
else if (panduan2 == 0)
{
AfxMessageBox(_T("请先进行平差"));
}
else
{
CPen pen;
pen.CreatePen(PS_SOLID, 3.6, RGB(0, 0, 255));//实线画笔
CPen *pOldPen;
pOldPen = pDC->SelectObject(&pen);
double ylength = karfa * (X02 - X01)/*-300*/;//y坐标轴长度
double xlength = karfa * (Y02 - Y01)/*-50*/;//x坐标轴长度
double Xmax, Xmin, Ymax, Ymin;
Xmax = Maxmin1x(KZD, KZDsums, 2) > Maxmin2x(WZD, unkownsunms, 2) ? Maxmin1x(KZD, KZDsums, 2) : Maxmin2x(WZD, unkownsunms, 2);
Xmin = Maxmin1x(KZD, KZDsums, 1) < Maxmin2x(WZD, unkownsunms, 1) ? Maxmin1x(KZD, KZDsums, 1) : Maxmin2x(WZD, unkownsunms, 1);
Ymax = Maxmin1y(KZD, KZDsums, 2) > Maxmin2y(WZD, unkownsunms, 2) ? Maxmin1y(KZD, KZDsums, 2) : Maxmin2y(WZD, unkownsunms, 2);
Ymin = Maxmin1y(KZD, KZDsums, 1) < Maxmin2y(WZD, unkownsunms, 1) ? Maxmin1y(KZD, KZDsums, 1) : Maxmin2y(WZD, unkownsunms, 1);//确定X、Y最值
double karfa2 = ((Xmax - Xmin) > (Ymax - Ymin)) ? ((Xmax - Xmin) / xlength) : ((Ymax - Ymin) / ylength);//实际坐标投影至图中的系数
double x0 = Y02 - (1 - karfa)*0.3*(Y02 - Y01)+30;
double y0 = X01 + (1 - karfa)*0.3*(X02 - X01)+100;//起始坐标 原点
CString str;//原点
str.Format(_T("%.f %.f"), Xmin , Ymin);
//绘制X轴
double temp_x001 = y0;
double temp_x002 = y0;
double temp_x003 = y0;
double temp_x004 = y0 - 7;
double temp_x005 = y0;
double temp_x006 = y0 + 7;
double temp_x007 = y0 - 10;
double temp_y001 = x0;
double temp_y002 = x0 - (0.25 + 0.75*karfa)*(Y02 - Y01);
double temp_y003 = x0 - (0.25 + 0.75*karfa)*(Y02 - Y01);
double temp_y004 = x0 - (0.25 + 0.75*karfa)*(Y02 - Y01) + 7;
double temp_y005 = x0 - (0.25 + 0.75*karfa)*(Y02 - Y01);
double temp_y006 = x0 - (0.25 + 0.75*karfa)*(Y02 - Y01) + 7;
double temp_y007 = x0 - (0.25 + 0.75*karfa)*(Y02 - Y01) -20;
pDC->MoveTo(temp_x001, temp_y001);
pDC->LineTo(temp_x002, temp_y002);
pDC->MoveTo(temp_x003, temp_y003);
pDC->LineTo(temp_x004, temp_y004);
pDC->MoveTo(temp_x005, temp_y005);
pDC->LineTo(temp_x006, temp_y006);
pDC->TextOut(temp_x007, temp_y007, _T("X"));
//绘制Y轴
temp_x001 = y0;
temp_x002 = y0 + (0.25 + 0.75*karfa)*(X02 - X01);
temp_x003 = y0 + (0.25 + 0.75*karfa)*(X02 - X01);
temp_x004 = y0 + (0.25 + 0.75*karfa)*(X02 - X01) - 7;
temp_x005 = y0 + (0.25 + 0.75*karfa)*(X02 - X01);
temp_x006 = y0 + (0.25 + 0.75*karfa)*(X02 - X01) -7;
temp_x007 = y0 + (0.25 + 0.75*karfa)*(X02 - X01);
temp_y001 = x0;
temp_y002 = x0;
temp_y003 = x0;
temp_y004 = x0 - 7;
temp_y005 = x0;
temp_y006 = x0+7 ;
temp_y007 = x0 -20;
pDC->MoveTo(temp_x001, temp_y001);
pDC->LineTo(temp_x002, temp_y002);
pDC->MoveTo(temp_x003, temp_y003);
pDC->LineTo(temp_x004, temp_y004);
pDC->MoveTo(temp_x005, temp_y005);
pDC->LineTo(temp_x006, temp_y006);
pDC->TextOut(temp_x007, temp_y007, _T("Y"));
//画平行Y轴的刻度
int tag_x = 5;//5条线
double temp_tag_x = xlength / tag_x;
double temp_x = temp_tag_x;
for (int i = 0; i < 5; i++)
{
double t_x = y0;
double t_y = x0 - temp_x;
double t_x2 = y0 + ylength;
double t_y2 = x0 - temp_x;
pDC->MoveTo(t_x , t_y );
pDC->LineTo(t_x2 , t_y2 );
CString str;
str.Format(_T("%.f"), Xmin + (i + 1)*(Xmax - Xmin) / 5);
double t_x3 = y0 - 75;
double t_y3 = x0 - temp_x;
pDC->TextOut(t_x3, t_y3, str);
temp_x += temp_tag_x;
}
//画平行X轴的刻度
int tag_y = 5;//5条线
double temp_tag_y = ylength / tag_y;
double temp_y = temp_tag_y;
for (int i = 0; i < 5; i++)
{
double t_x = y0 + temp_y;
double t_y = x0;
double t_x2 = y0 + temp_y;
double t_y2 = x0 - xlength;//错误
pDC->MoveTo(t_x, t_y );
pDC->LineTo(t_x2 , t_y2 );
CString str;
str.Format(_T("%.f"), Ymin + (i + 1)*(Ymax - Ymin) / 5);
double t_x3 = y0 + temp_y;
double t_y3 = x0 ;
pDC->TextOut(t_x3, t_y3, str);
temp_y += temp_tag_y;
}
//方向观测值连线
for (int i = 0; i < Ganglesums; i++)
{
CPen pen;
pen.CreatePen(PS_SOLID, 0.8, RGB(255, 0, 0));//实线画笔
CPen *pOldPen;
pOldPen = pDC->SelectObject(&pen);
double t_x = (GCJ[i].Qizhan->Y - Ymin) / karfa2 + y0;
double t_y = x0 - (GCJ[i].Qizhan->X - Xmin) / karfa2;
double t_x2 = (GCJ[i].Zhaozhan->Y - Ymin) / karfa2 + y0 ;
double t_y2 = x0 - (GCJ[i].Zhaozhan->X - Xmin) / karfa2;
pDC->MoveTo(t_x, t_y );
pDC->LineTo(t_x2, t_y2);
pen.DeleteObject();
}
//画误差椭圆
double karfa3 = (0.8 / karfa) *(WZD[0].E) / 5;//比例系数
for (int i = 0; i < unkownsunms; i++)
{
CPen pen;
pen.CreatePen(PS_SOLID, 1.8, RGB(20, 20, 20));//实线画笔
CPen *pOldPen;
pOldPen = pDC->SelectObject(&pen);
for (int j = 0; j < 120; j ++)
{
//画椭圆
double dAlf = j * 2 * pi / 120;
double xae, ybf;
double c = 0;
double tralatazi;
xae = WZD[i].E / karfa3 * cos(dAlf);
ybf = WZD[i].F / karfa3 * sin(dAlf);
tralatazi = WZD[i].Q + pi / 2;
double temp_1 = xae * cos(tralatazi) + ybf * sin(tralatazi) + (WZD[i].Y - Ymin) / karfa2 + y0 ;
double temp_2 = -ybf * cos(tralatazi) + xae * sin(tralatazi) + x0 - (WZD[i].X - Xmin) / karfa2 ;
if (j == 0)
{
pDC->MoveTo(temp_1 , temp_2 );
}//防止从椭圆的长短轴而不是中心连接下一个点
pDC->LineTo(temp_1 , temp_2 );
}
double temp1 = (WZD[i].Y - Ymin) / karfa2 + y0 + (WZD[i].F*sin(WZD[i].Q + pi / 2)) / karfa3 ;//短轴右上角 x
double temp2 = x0 - (WZD[i].X - Xmin) / karfa2 - (WZD[i].F*cos(WZD[i].Q + pi / 2)) / karfa3 ;//短轴右上角 y
double temp3 = (WZD[i].Y - Ymin) / karfa2 + y0 - (WZD[i].F*sin(WZD[i].Q + pi / 2)) / karfa3 ;//短轴左下角 x
double temp4 = x0 - (WZD[i].X - Xmin) / karfa2 + (WZD[i].F*cos(WZD[i].Q + pi / 2)) / karfa3 ;//短轴左下角 y
pDC->MoveTo(temp1 , temp2);
pDC->LineTo(temp3 , temp4);
pen.DeleteObject();
double _temp1 = (WZD[i].Y - Ymin) / karfa2 + y0 + (WZD[i].E*cos(WZD[i].Q + pi / 2)) / karfa3 ;//长轴右下角 x
double _temp2 = x0 - (WZD[i].X - Xmin) / karfa2 + (WZD[i].E*sin(WZD[i].Q + pi / 2)) / karfa3 ;//长轴右上角 y
double _temp3 = (WZD[i].Y - Ymin) / karfa2 + y0 - (WZD[i].E*cos(WZD[i].Q + pi / 2)) / karfa3 ;//长轴左上角 x
double _temp4 = x0 - (WZD[i].X - Xmin) / karfa2 - (WZD[i].E*sin(WZD[i].Q + pi / 2)) / karfa3 ;//长轴左上角 y
pDC->MoveTo(_temp1, _temp2);
pDC->LineTo(_temp3, _temp4 );
}
for (int i = 0; i < unkownsunms; i++)//画未知点点号
{
CString str;
str.Format(_T("%s"), WZD[i].dianhao);
double temp_1 = (WZD[i].Y - Ymin) / karfa2 + y0 ;
double temp_2 = x0 - (WZD[i].X - Xmin) / karfa2 ;
pDC->TextOut(temp_1 , temp_2 , str);
}
for (int i = 0; i < KZDsums; i++)//画已知点点号
{
CString str;
str.Format(_T("%s"), KZD[i].dianhao);
double temp_1 = (KZD[i].Y - Ymin) / karfa2 + y0 ;
double temp_2 = x0 - (KZD[i].X - Xmin) / karfa2;
huiKZD(pDC, temp_1, temp_2 , 50, karfa-0.5 );
pDC->TextOut(temp_1 , temp_2, str);
}
}
}
<主对话框.cpp>
#include "Data.h"
#include"Length.h"
#include"Gangle.h"
#include"support.h"
#include"Draw.h"//画图对话框名称
support k;
Draw o;
//文本显示框绑定的为的Cstring变量为out
void CSHIXIDSDlg::OnBnClickedButton1()//读取数据并显示
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
k.cunchu.Empty();
double a = k.read();
out = k.cunchu;
UpdateData(FALSE);
}
void CSHIXIDSDlg::OnBnClickedButton2()//输出概算结果
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
k.cunchu1.Empty();
double b = k.gaisuan();//先运行概算
out = k.cunchu1;
UpdateData(FALSE);
}
void CSHIXIDSDlg::OnBnClickedButton3()//输出平差结果
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
k.cunchu2.Empty();
double c = k.pingcha();//先运行平差
out = k.cunchu2;
UpdateData(FALSE);
}
void CSHIXIDSDlg::OnBnClickedButton4()//进行画图
{
// TODO: 在此添加控件通知处理程序代码
Draw abc;
abc.o = k;
abc.DoModal();
}
void CSHIXIDSDlg::OnBnClickedButton5()//退出
{
// TODO: 在此添加控件通知处理程序代码
CDialogEx::OnCancel();
}
<Draw.cpp>
//头文件自行添加
support o;
void Draw::OnBnClickedButton1()//画图
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
CDC* pDC = GetDlgItem(IDC_STATIC)->GetDC();
GetDlgItem(IDC_STATIC)->UpdateWindow();
CRect rc;
GetDlgItem(IDC_STATIC)->GetWindowRect(&rc);
GetWindowRect(&rc);
o.huitu(pDC, rc, 0.9);
UpdateData(FALSE);
}
void Draw::OnBnClickedButton2()//退出
{
// TODO: 在此添加控件通知处理程序代码
CDialogEx::OnCancel();
}
运行结果
答辩高分总结
答辩分为两部分:
1、修改程序(时间最好控制在三十分钟以内可以保证A,时间越长分越低,重点在画图部分,修改程序完成后,老师只看运行结果,或者问原理,不会看代码)
2、老师问问题(只要程序是自己做的,几乎没有问题,老师一般只问五六行代码是什么意思且集中在画图前的部分,所以重点在修改程序)
修改程序问题汇总:
每人改两个程序
1、一个简单的:诸如修改数据格式后读取数据、输出权矩阵P的对角线元素等等随机选一个,不必准备。
2、一个稍复杂的:集中在画图部分,主要是将误差椭圆呈现在画图区域中心、误差椭圆放大缩小、误差椭圆旋转、将图像呈现在新的对话框中(本程序已改)等随机选一个,可以提前练习一下,十分简单。
修改程序提前练习一下,至少可以得A(优)。
设计时间分配
一周时间足够将程序写完,重点要理解概算和平差的详细步骤,画图部分代码可以直接粘贴,不过要仔细理解每个变量所对应的图像内容。
程序遇到问题时要学会设断点调试!!!
只要认为自己的算法没问题,一般问题就是代码的变量顺序反了,或者是<和>搞错了等问题。