目录
首先展示一下此程序可读取的.txt文件的正确格式
6,3,2
A,3143.237,5260.334
B,4609.361,5025.696
C,4157.197,8853.254
D,3822.911,9795.726
A
B,L,0
P1,L,44.0545
P1,S,2185.070
B
P1,L,0
A,L,93.1043
P1
A,L,0
B,L,42.4327
B,S,1522.853
P2,L,244.3218
P2,S,1500.017
P2
P1,L,0
C,L,201.5734
C,S,1009.021
C
P2,L,0
D,L,168.0145
引用及预处理方法的设计
引用
读取.txt后缀文件,需要作引用,需要引用的内容如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
注意,这是程序能正常运行的完整引用,并不只是处理.txt文件所需的引用。
读取方法
接下来就是读取,这里在对应的窗体类中设计一个void函数来进行读取:
/// <summary>
/// 读取文件
/// </summary>
/// <returns></returns>
private void ReadDoc()
{
observedDatas = new List<ObservedData>();
OpenFileDialog open = new OpenFileDialog();
if (open.ShowDialog() != DialogResult.OK)
{
return;
}
StreamReader reader = new StreamReader(open.FileName);
//读取已知数据
string[] s = reader.ReadLine().Split(',');
knownData = new KnownData(Convert.ToDouble(s[0]), Convert.ToDouble(s[1]), Convert.ToDouble(s[2]));
while (true)
{
s = reader.ReadLine().Split(',');
if (s.Length != 3) break;
knownData.pointDatas.Add(new PointData(s[0], Convert.ToDouble(s[1]), Convert.ToDouble(s[2])));
}
while (!reader.EndOfStream)
{
ObservedData observedData = new ObservedData(s[0]);
while (!reader.EndOfStream)
{
s = reader.ReadLine().Split(',');
if (s.Length != 3) break;
observedData.originalDatas.Add(new OriginalData(s[0], s[1], Convert.ToDouble(s[2])));
}
observedDatas.Add(observedData);
}
DataTable table = new DataTable();
}
相关类及方法的设计
这个方法中,有自主设计的类,KnowData类、ObservedData类。此外还有需要在近似平差中使用的PointData类,其设计及内置方法如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 水平网平差程序
{
/// <summary>
/// 已知数据
/// </summary>
class KnownData
{
public double directionError, sideError, ratioError;
public List<PointData> pointDatas;
public KnownData(double directionError, double sideError, double ratioError)
{
this.directionError = directionError;
this.sideError = sideError;
this.ratioError = ratioError;
this.pointDatas = new List<PointData>();
}
}
/// <summary>
/// 已知点数据
/// </summary>
class PointData
{
public string id;
public double x, y;
public PointData(string id, double x, double y)
{
this.id = id;
this.x = x;
this.y = y;
}
}
/// <summary>
/// 观测数据
/// </summary>
class ObservedData
{
public string testSiteNum;
public List<OriginalData> originalDatas;
public ObservedData(string testSiteNum)
{
this.testSiteNum = testSiteNum;
this.originalDatas = new List<OriginalData>();
}
}
/// <summary>
/// 照准点数据
/// </summary>
class OriginalData
{
public string id;
public string type;
public double value;
public OriginalData(string id, string type, double value)
{
this.id = id;
this.type = type;
this.value = value;
}
}
}
之后设计角度等的简单计算:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 水平网平差程序
{
/// <summary>
/// 基本运算
/// 包括:角度弧度互化、坐标方位角计算
/// </summary>
class BasicCal
{
/// <summary>
/// 角度转弧度
/// 适用于格式为dd.mmss
/// </summary>
/// <param name="dms"></param>
/// <returns></returns>
public static double Dms2rad(double dms)
{
double d = Math.Floor(dms);
double m = Math.Floor((dms - d) * 100.0);
double s = (dms - d - m / 100.0) * 10000.0;
return (d + m / 60.0 + s / 3600.0) * Math.PI / 180.0;
}
/// <summary>
/// 弧度转角度
/// </summary>
/// <param name="rad"></param>
/// <returns></returns>
public static double Rad2dms(double rad)
{
double temp = rad * 180 / Math.PI;
double d = Math.Floor(temp);
double m = Math.Floor((temp - d) * 60);
double s = Math.Floor((temp - d - m / 60.0) * 3600);
return d + m / 100.0 + s / 10000.0;
}
/// <summary>
/// 求坐标方位角
/// </summary>
/// <param name="xA"></param>
/// <param name="yA"></param>
/// <param name="xB"></param>
/// <param name="yB"></param>
/// <returns></returns>
public static double CoordinateAzimuth(double xA, double yA, double xB, double yB)
{
if (yB - yA < 0)
{
return Math.Atan2(yB - yA, xB - xA) + 2.0 * Math.PI;
}
if (xB - xA == 0 && yB - yA >= 0)
{
return Math.PI / 2.0;
}
if (xB - xA == 0 && yB - yA < 0)
{
return Math.PI * 3.0 / 2.0;
}
return Math.Atan2(yB - yA, xB - xA);
}
}
}
最后是近似平差类及方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 水平网平差程序
{
/// <summary>
/// 导线网近似坐标计算
/// </summary>
class ApproximateCoordinate
{
public List<PointData> points;
public ApproximateCoordinate(KnownData knownData, List<ObservedData> observedDatas)
{
this.points = new List<PointData>();
foreach (ObservedData observedData in observedDatas)
{
//从已知数据中寻找相应点号坐标
PointData pA = knownData.pointDatas.Find(item => item.id == observedData.testSiteNum);
if (pA == null)
{
//若已知数据不存在相应点号,则到已算近似坐标中寻找
pA = points.Find(item => item.id == observedData.testSiteNum);
if (pA == null)
{
//若已知数据和已算近视坐标均找不到则数据有误
MessageBox.Show("数据有误");
return;
}
}
//同理查找第一个照准点
PointData pB = knownData.pointDatas.Find(item => item.id == observedData.originalDatas[0].id);
//points.Add(pB);
if (pB == null)
{
pB = points.Find(item => item.id == observedData.originalDatas[0].id);
if (pB == null)
{
MessageBox.Show("数据有误");
return;
}
}
//计算AB的坐标方位角
double alphaAB = BasicCal.CoordinateAzimuth(pA.x, pA.y, pB.x, pB.y) - observedData.originalDatas[0].value;
//循环计算该组数据的其他照准点近似坐标
for (int i = 1; i < observedData.originalDatas.Count; i++)
{
//若为已知数据直接加入
PointData tempP = knownData.pointDatas.Find(item => item.id == observedData.originalDatas[i].id);
if (tempP != null)
{
//points.Add(tempP);
continue;
}
//只要角度观测值
if (knownData.pointDatas.Exists(item => item.id == observedData.originalDatas[i].id) || observedData.originalDatas[i].type == "S" || points.Exists(item => item.id == observedData.originalDatas[i].id))
{
continue;
}
//计算近似点坐标
double xA = pA.x;
double yA = pA.y;
double sAP = observedData.originalDatas.Find(item => item.id == observedData.originalDatas[i].id && item.type == "S").value;
double AlphaAP = alphaAB + BasicCal.Dms2rad(observedData.originalDatas[i].value);
double cosAlphaAP = Math.Cos(AlphaAP);
double sinAlphaAP = Math.Sin(AlphaAP);
points.Add(new PointData(observedData.originalDatas[i].id, xA + sAP * cosAlphaAP, yA + sAP * sinAlphaAP));
}
}
}
}
}
窗体类后续方法的设计及调用
这里采取Datagridview控件储存及处理数据
设计两个Name属性分别为 已知点 和 观测值 的Datagirdview在窗体内,不做其他设计,之后在窗体中设计ShowTable方法,用于将数据读入控件:
private void ShowTable()
{
//已知数据显示
DataTable table1 = new DataTable();
table1.Columns.Add("已知点点号");
table1.Columns.Add("X坐标");
table1.Columns.Add("Y坐标");
foreach (PointData p in knownData.pointDatas)
{
DataRow row = table1.NewRow();
row["已知点点号"] = p.id;
row["X坐标"] = p.x;
row["Y坐标"] = p.y;
table1.Rows.Add(row);
}
已知点.DataSource = table1;
//观测数据显示
DataTable table2 = new DataTable();
table2.Columns.Add("观测点点号");
table2.Columns.Add("照准点点号");
table2.Columns.Add("观测值类型");
table2.Columns.Add("观测值");
foreach (ObservedData observedData in observedDatas)
{
foreach (OriginalData P in observedData.originalDatas)
{
DataRow row = table2.NewRow();
row["观测点点号"] = observedData.testSiteNum;
row["照准点点号"] = P.id;
row["观测值类型"] = P.type;
row["观测值"] = P.value;
table2.Rows.Add(row);
}
}
已知点.DataSource = table1;
观测值.DataSource = table2;
}
在点击 打开 按钮时调用:
private void 打开_Click(object sender, EventArgs e)
{
try
{
ReadDoc();
ShowTable();
}
catch
{
MessageBox.Show("文件格式不符");
}
}
之后是在单击某个控件时进行计算,这里使用Name为 计算 的 按钮 控件:
private void 计算_Click(object sender, EventArgs e)
{
try
{
approximateCoordinate = new ApproximateCoordinate(knownData, observedDatas);
ShowText();
}
catch
{
MessageBox.Show("计算错误");
}
}
接下来,是将计算结果写入某控件,这里采取的是 Name 属性为 报告 的 richtextbox:
private void ShowText()
{
报告.Text += " 近似坐标值:\n";
报告.Text += string.Format("{0,14}", "点名") + string.Format("{0,14}", "X坐标") + string.Format("{0,14}", "Y坐标") + "\n";
foreach (PointData pointData in knownData.pointDatas)
{
报告.Text += string.Format("{0,16}", pointData.id) + string.Format("{0,16}", pointData.x) + string.Format("{0,16}", pointData.y) + "\n";
}
foreach (PointData pointData in approximateCoordinate.points)
{
报告.Text += string.Format("{0,16}", pointData.id) + string.Format("{0,16}", pointData.x.ToString("0.000")) + string.Format("{0,16}", pointData.y.ToString("0.000")) + "\n";
}
}
最后则是将结果写入.txt文件,同样在单击按钮时进行:
private void 保存_Click(object sender, EventArgs e)
{
SaveFileDialog save = new SaveFileDialog();
save.Filter = "(文本文件)|.txt";
if (save.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(save.FileName);
sw.Write(报告.Text);
sw.Close();
}
}
完整的窗体类设计
完整的窗体类设计如下所示:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 水平网平差程序
{
public partial class 导线网近似平差 : Form
{
public 导线网近似平差()
{
InitializeComponent();
StartPosition = FormStartPosition.CenterScreen;
}
KnownData knownData;
List<ObservedData> observedDatas;
ApproximateCoordinate approximateCoordinate;
IndirectAdjustment indirectAdjustment;
private void 打开_Click(object sender, EventArgs e)
{
try
{
ReadDoc();
ShowTable();
}
catch
{
MessageBox.Show("文件格式不符");
}
}
private void 计算_Click(object sender, EventArgs e)
{
try
{
approximateCoordinate = new ApproximateCoordinate(knownData, observedDatas);
ShowText();
展示框.SelectedTab = 报告页;
}
catch
{
MessageBox.Show("计算错误");
}
}
private void 保存_Click(object sender, EventArgs e)
{
SaveFileDialog save = new SaveFileDialog();
save.Filter = "(文本文件)|.txt";
if (save.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(save.FileName);
sw.Write(报告.Text);
sw.Close();
}
}
/// <summary>
/// 读取文件
/// </summary>
/// <returns></returns>
private void ReadDoc()
{
observedDatas = new List<ObservedData>();
OpenFileDialog open = new OpenFileDialog();
if (open.ShowDialog() != DialogResult.OK)
{
return;
}
StreamReader reader = new StreamReader(open.FileName);
//读取已知数据
string[] s = reader.ReadLine().Split(',');
knownData = new KnownData(Convert.ToDouble(s[0]), Convert.ToDouble(s[1]), Convert.ToDouble(s[2]));
while (true)
{
s = reader.ReadLine().Split(',');
if (s.Length != 3) break;
knownData.pointDatas.Add(new PointData(s[0], Convert.ToDouble(s[1]), Convert.ToDouble(s[2])));
}
while (!reader.EndOfStream)
{
ObservedData observedData = new ObservedData(s[0]);
while (!reader.EndOfStream)
{
s = reader.ReadLine().Split(',');
if (s.Length != 3) break;
observedData.originalDatas.Add(new OriginalData(s[0], s[1], Convert.ToDouble(s[2])));
}
observedDatas.Add(observedData);
}
DataTable table = new DataTable();
}
private void ShowTable()
{
//已知数据显示
DataTable table1 = new DataTable();
table1.Columns.Add("已知点点号");
table1.Columns.Add("X坐标");
table1.Columns.Add("Y坐标");
foreach (PointData p in knownData.pointDatas)
{
DataRow row = table1.NewRow();
row["已知点点号"] = p.id;
row["X坐标"] = p.x;
row["Y坐标"] = p.y;
table1.Rows.Add(row);
}
已知点.DataSource = table1;
//观测数据显示
DataTable table2 = new DataTable();
table2.Columns.Add("观测点点号");
table2.Columns.Add("照准点点号");
table2.Columns.Add("观测值类型");
table2.Columns.Add("观测值");
foreach (ObservedData observedData in observedDatas)
{
foreach (OriginalData P in observedData.originalDatas)
{
DataRow row = table2.NewRow();
row["观测点点号"] = observedData.testSiteNum;
row["照准点点号"] = P.id;
row["观测值类型"] = P.type;
row["观测值"] = P.value;
table2.Rows.Add(row);
}
}
已知点.DataSource = table1;
观测值.DataSource = table2;
}
private void ShowText()
{
报告.Text += " 近似坐标值:\n";
报告.Text += string.Format("{0,14}", "点名") + string.Format("{0,14}", "X坐标") + string.Format("{0,14}", "Y坐标") + "\n";
foreach (PointData pointData in knownData.pointDatas)
{
报告.Text += string.Format("{0,16}", pointData.id) + string.Format("{0,16}", pointData.x) + string.Format("{0,16}", pointData.y) + "\n";
}
foreach (PointData pointData in approximateCoordinate.points)
{
报告.Text += string.Format("{0,16}", pointData.id) + string.Format("{0,16}", pointData.x.ToString("0.000")) + string.Format("{0,16}", pointData.y.ToString("0.000")) + "\n";
}
}
}
}