C#进阶(一)——TXT文件处理:以导线网近似平差为例

目录

引用及预处理方法的设计

引用

读取方法

相关类及方法的设计

窗体类后续方法的设计及调用

完整的窗体类设计


首先展示一下此程序可读取的.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";
            }
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值