导线网平差程序系统设计

本程序提供了导线网平差所用到的全部C++代码,在MFC窗口内调试后可直接运行。尝试

原始数据(格式)

2021071810303196.jpg

界面设计 

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NzA1NjY2MQ==,size_16,color_FFFFFF,t_70

 点击画图按钮后弹出的对话框

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NzA1NjY2MQ==,size_16,color_FFFFFF,t_70

类的设计

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();
}

运行结果

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NzA1NjY2MQ==,size_16,color_FFFFFF,t_70

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NzA1NjY2MQ==,size_16,color_FFFFFF,t_70

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NzA1NjY2MQ==,size_16,color_FFFFFF,t_70

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81NzA1NjY2MQ==,size_16,color_FFFFFF,t_70

答辩高分总结

答辩分为两部分:

1、修改程序(时间最好控制在三十分钟以内可以保证A,时间越长分越低,重点在画图部分,修改程序完成后,老师只看运行结果,或者问原理,不会看代码)

2、老师问问题(只要程序是自己做的,几乎没有问题,老师一般只问五六行代码是什么意思且集中在画图前的部分,所以重点在修改程序)

修改程序问题汇总:

       每人改两个程序

      1、一个简单的:诸如修改数据格式后读取数据、输出权矩阵P的对角线元素等等随机选一个,不必准备。

       2、一个稍复杂的:集中在画图部分,主要是将误差椭圆呈现在画图区域中心、误差椭圆放大缩小、误差椭圆旋转、将图像呈现在新的对话框中(本程序已改)等随机选一个,可以提前练习一下,十分简单。

修改程序提前练习一下,至少可以得A(优)。

设计时间分配

       一周时间足够将程序写完,重点要理解概算和平差的详细步骤,画图部分代码可以直接粘贴,不过要仔细理解每个变量所对应的图像内容。

       程序遇到问题时要学会设断点调试!!!

       只要认为自己的算法没问题,一般问题就是代码的变量顺序反了,或者是<和>搞错了等问题。

 

 

  • 10
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓学僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值