From dc9ca11cec9ad532b826de430826c6807e6285f3 Mon Sep 17 00:00:00 2001 From: biss Date: Tue, 16 Jun 2026 12:57:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=80=E5=90=8E=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Forms/MainForm.Designer.cs | 7 +- Forms/MainForm.cs | 283 +++++++++++++++++++++-------------- Forms/ResultForm.cs | 35 +++++ Models/LeastSquaresResult.cs | 7 +- Services/LeastSquares.cs | 21 ++- Services/Report.cs | 147 +++++++++++++++++- 6 files changed, 374 insertions(+), 126 deletions(-) create mode 100644 Forms/ResultForm.cs diff --git a/Forms/MainForm.Designer.cs b/Forms/MainForm.Designer.cs index 0834222..10bf9ba 100644 --- a/Forms/MainForm.Designer.cs +++ b/Forms/MainForm.Designer.cs @@ -102,6 +102,7 @@ button2.TabIndex = 4; button2.Text = "查看结果"; button2.UseVisualStyleBackColor = true; + button2.Click += button2_Click; // // button3 // @@ -162,7 +163,7 @@ // 数据输入ToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { 从文件ToolStripMenuItem, 手动输入ToolStripMenuItem }); 数据输入ToolStripMenuItem.Name = "数据输入ToolStripMenuItem"; - 数据输入ToolStripMenuItem.Size = new Size(270, 34); + 数据输入ToolStripMenuItem.Size = new Size(218, 34); 数据输入ToolStripMenuItem.Text = "数据输入"; // // 从文件ToolStripMenuItem @@ -182,14 +183,14 @@ // 删除当前数据ToolStripMenuItem // 删除当前数据ToolStripMenuItem.Name = "删除当前数据ToolStripMenuItem"; - 删除当前数据ToolStripMenuItem.Size = new Size(270, 34); + 删除当前数据ToolStripMenuItem.Size = new Size(218, 34); 删除当前数据ToolStripMenuItem.Text = "删除当前数据"; 删除当前数据ToolStripMenuItem.Click += 删除当前数据ToolStripMenuItem_Click; // // 数据检查ToolStripMenuItem // 数据检查ToolStripMenuItem.Name = "数据检查ToolStripMenuItem"; - 数据检查ToolStripMenuItem.Size = new Size(270, 34); + 数据检查ToolStripMenuItem.Size = new Size(218, 34); 数据检查ToolStripMenuItem.Text = "数据检查"; 数据检查ToolStripMenuItem.Click += 数据检查ToolStripMenuItem_Click; // diff --git a/Forms/MainForm.cs b/Forms/MainForm.cs index 37a1c48..92df45b 100644 --- a/Forms/MainForm.cs +++ b/Forms/MainForm.cs @@ -1,37 +1,33 @@ -using kcsj.Models; +using kcsj.Models; using kcsj.Services; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; +using System.Diagnostics; using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; namespace kcsj.Forms { public partial class MainForm : Form { + private LeastSquaresResult? lastResult; public MainForm() { InitializeComponent(); + button3.Click += button3_Click; } private void btnDataInput_Click(object sender, EventArgs e) { DataInputForm form = new DataInputForm(); form.ShowDialog(); + lastResult = null; } private void MainForm_Load(object sender, EventArgs e) { LogService.OnLog += ShowLog; - LogService.AddLog("程序启动成功。"); } + private void ShowLog(string message) { LOG.AppendText(message + "\r\n"); @@ -47,13 +43,14 @@ namespace kcsj.Forms { FileInputForm form = new FileInputForm(); form.ShowDialog(); + lastResult = null; } private void 手动输入ToolStripMenuItem_Click(object sender, EventArgs e) { ManualInputForm form = new ManualInputForm(); - form.ShowDialog(); + lastResult = null; } private void 关于ToolStripMenuItem_Click(object sender, EventArgs e) @@ -63,123 +60,27 @@ namespace kcsj.Forms private void 开始平差ToolStripMenuItem_Click(object sender, EventArgs e) { - try - { - if (!DataStore.HasData) - { - MessageBox.Show("请先导入或输入已知点和观测数据。"); - return; - } - - LeastSquaresResult result = - LeastSquaresAdjustmentService.Adjust( - DataStore.KnownPoints, - DataStore.Observations); - - MessageBox.Show("间接平差计算完成。"); - - // 示例:把未知点结果输出到日志 - foreach (var item in result.UnknownElevations) - { - string pointName = item.Key; - double elevation = item.Value; - double error = result.UnknownElevationErrors[pointName]; - - LogService.AddLog( - $"{pointName} 平差高程 = {elevation:F4} m,中误差 = ±{error:F4} m"); - } - - // 示例:输出观测改正数 - foreach (var obsResult in result.ObservationResults) - { - LogService.AddLog( - $"第{obsResult.Index}段 {obsResult.FromPoint}->{obsResult.ToPoint}:" + - $"v = {obsResult.Residual:F6},平差后高差 = {obsResult.AdjustedHeightDiff:F6}"); - } - } - catch (Exception ex) - { - MessageBox.Show("平差失败:" + ex.Message); - LogService.AddLog("平差失败:" + ex.Message); - } + RunAdjustment(); } private void 查看结果ToolStripMenuItem_Click(object sender, EventArgs e) { - + ShowAdjustmentResult(); } private void 输出报告ToolStripMenuItem_Click(object sender, EventArgs e) { - + ExportReport(); } private void btnDataInspect_Click(object sender, EventArgs e) { - DataCheckResult result = DataCheck.Check(DataStore.KnownPoints, DataStore.Observations); - - LogService.AddLog(result.ToLogText()); - LogService.AddLog(Environment.NewLine); - - if (!result.IsValid) - { - MessageBox.Show( - "数据检查未通过,请查看日志信息。", - "数据检查", - MessageBoxButtons.OK, - MessageBoxIcon.Warning); - - return; - } - - MessageBox.Show( - "数据检查通过,可以进行平差计算。", - "数据检查", - MessageBoxButtons.OK, - MessageBoxIcon.Information); + CheckData(); } private void btnStartAdjust_Click(object sender, EventArgs e) { - try - { - if (!DataStore.HasData) - { - MessageBox.Show("请先导入或输入已知点和观测数据。"); - return; - } - - LeastSquaresResult result = - LeastSquaresAdjustmentService.Adjust( - DataStore.KnownPoints, - DataStore.Observations); - - MessageBox.Show("间接平差计算完成。"); - - // 示例:把未知点结果输出到日志 - foreach (var item in result.UnknownElevations) - { - string pointName = item.Key; - double elevation = item.Value; - double error = result.UnknownElevationErrors[pointName]; - - LogService.AddLog( - $"{pointName} 平差高程 = {elevation:F4} m,中误差 = ±{error:F4} m"); - } - - // 示例:输出观测改正数 - foreach (var obsResult in result.ObservationResults) - { - LogService.AddLog( - $"第{obsResult.Index}段 {obsResult.FromPoint}->{obsResult.ToPoint}:" + - $"v = {obsResult.Residual:F6},平差后高差 = {obsResult.AdjustedHeightDiff:F6}"); - } - } - catch (Exception ex) - { - MessageBox.Show("平差失败:" + ex.Message); - LogService.AddLog("平差失败:" + ex.Message); - } + RunAdjustment(); } private void 删除当前数据ToolStripMenuItem_Click(object sender, EventArgs e) @@ -188,22 +89,36 @@ namespace kcsj.Forms "确定要清空当前数据吗?", "二次确认", MessageBoxButtons.YesNo, - MessageBoxIcon.Warning - ); + MessageBoxIcon.Warning); if (result == DialogResult.Yes) { DataStore.Clear(); + lastResult = null; LogService.AddLog("当前数据已清空"); } else { - this.Close(); LogService.AddLog("用户取消清空数据"); } } private void 数据检查ToolStripMenuItem_Click(object sender, EventArgs e) + { + CheckData(); + } + + private void button2_Click(object sender, EventArgs e) + { + ShowAdjustmentResult(); + } + + private void button3_Click(object? sender, EventArgs e) + { + ExportReport(); + } + + private void CheckData() { DataCheckResult result = DataCheck.Check(DataStore.KnownPoints, DataStore.Observations); @@ -227,5 +142,143 @@ namespace kcsj.Forms MessageBoxButtons.OK, MessageBoxIcon.Information); } + + private bool RunAdjustment() + { + try + { + if (!DataStore.HasData) + { + MessageBox.Show("请先导入或输入已知点和观测数据。"); + return false; + } + + LeastSquaresResult result = LeastSquaresAdjustmentService.Adjust( + DataStore.KnownPoints, + DataStore.Observations); + + lastResult = result; + MessageBox.Show("间接平差计算完成。"); + + foreach (KeyValuePair item in result.UnknownElevations) + { + string pointName = item.Key; + double elevation = item.Value; + double error = result.UnknownElevationErrors[pointName]; + + LogService.AddLog( + $"{pointName} 平差高程 = {elevation:F4} m,中误差 = ±{FormatValue(error, 4)} m"); + } + + foreach (ObservationAdjustmentResult obsResult in result.ObservationResults) + { + LogService.AddLog( + $"第{obsResult.Index}段 {obsResult.FromPoint}->{obsResult.ToPoint}:" + + $"v = {obsResult.Residual:F6},平差后高差 = {obsResult.AdjustedHeightDiff:F6}," + + $"中误差 = ±{FormatValue(obsResult.AdjustedHeightDiffError, 6)} m"); + } + + return true; + } + catch (Exception ex) + { + MessageBox.Show("平差失败:" + ex.Message); + LogService.AddLog("平差失败:" + ex.Message); + return false; + } + } + + private LeastSquaresResult? GetResultOrRunAdjustment() + { + if (lastResult != null) + { + return lastResult; + } + + DialogResult choice = MessageBox.Show( + "当前还没有平差结果,是否立即进行平差计算?", + "平差结果", + MessageBoxButtons.YesNo, + MessageBoxIcon.Question); + + if (choice != DialogResult.Yes) + { + return null; + } + + return RunAdjustment() ? lastResult : null; + } + + private void ShowAdjustmentResult() + { + LeastSquaresResult? result = GetResultOrRunAdjustment(); + if (result == null) + { + return; + } + + using ResultForm form = new ResultForm(result); + form.ShowDialog(this); + } + + private void ExportReport() + { + LeastSquaresResult? result = GetResultOrRunAdjustment(); + if (result == null) + { + return; + } + + using FolderBrowserDialog dialog = new FolderBrowserDialog + { + Description = "请选择成果文件和报告文件的输出目录", + UseDescriptionForTitle = true + }; + + if (dialog.ShowDialog(this) != DialogResult.OK) + { + return; + } + + string heightPath = Path.Combine(dialog.SelectedPath, "height.txt"); + string surveyPath = Path.Combine(dialog.SelectedPath, "survey.txt"); + string reportPath = Path.Combine(dialog.SelectedPath, "report.txt"); + + File.WriteAllText(heightPath, Report.BuildHeightText(result), Encoding.UTF8); + File.WriteAllText(surveyPath, Report.BuildSurveyText(result), Encoding.UTF8); + File.WriteAllText( + reportPath, + Report.BuildReportText(DataStore.KnownPoints, DataStore.Observations, result), + Encoding.UTF8); + + LogService.AddLog($"高程成果文件已输出:{heightPath}"); + LogService.AddLog($"高差成果文件已输出:{surveyPath}"); + LogService.AddLog($"平差报告已输出:{reportPath}"); + + DialogResult openChoice = MessageBox.Show( + "输出完成,是否打开输出目录?", + "输出报告", + MessageBoxButtons.YesNo, + MessageBoxIcon.Information); + + if (openChoice == DialogResult.Yes) + { + Process.Start(new ProcessStartInfo + { + FileName = dialog.SelectedPath, + UseShellExecute = true + }); + } + } + + private static string FormatValue(double value, int digits) + { + if (double.IsNaN(value) || double.IsInfinity(value)) + { + return "无法计算"; + } + + return value.ToString($"F{digits}"); + } } } diff --git a/Forms/ResultForm.cs b/Forms/ResultForm.cs new file mode 100644 index 0000000..9f355a6 --- /dev/null +++ b/Forms/ResultForm.cs @@ -0,0 +1,35 @@ +using kcsj.Models; +using kcsj.Services; + +namespace kcsj.Forms +{ + public partial class ResultForm : Form + { + private RichTextBox resultTextBox = null!; + + public ResultForm(LeastSquaresResult result) + { + InitializeComponent(); + resultTextBox.Text = Report.BuildResultText(result); + } + + private void InitializeComponent() + { + Text = "平差结果"; + StartPosition = FormStartPosition.CenterParent; + Size = new Size(820, 560); + MinimumSize = new Size(680, 420); + + resultTextBox = new RichTextBox + { + Dock = DockStyle.Fill, + ReadOnly = true, + BorderStyle = BorderStyle.FixedSingle, + Font = new Font("Consolas", 10.5F), + WordWrap = false + }; + + Controls.Add(resultTextBox); + } + } +} diff --git a/Models/LeastSquaresResult.cs b/Models/LeastSquaresResult.cs index 9a880e6..8e917b4 100644 --- a/Models/LeastSquaresResult.cs +++ b/Models/LeastSquaresResult.cs @@ -64,5 +64,10 @@ namespace kcsj.Models /// 平差后高差 h + v /// public double AdjustedHeightDiff { get; set; } + + /// + /// 平差后高差中误差 + /// + public double AdjustedHeightDiffError { get; set; } } -} \ No newline at end of file +} diff --git a/Services/LeastSquares.cs b/Services/LeastSquares.cs index 3e41ee7..18eb3e0 100644 --- a/Services/LeastSquares.cs +++ b/Services/LeastSquares.cs @@ -205,6 +205,22 @@ namespace kcsj.Services double residual = V[i, 0]; double adjustedHeightDiff = obs.HeightDiff + residual; + double adjustedHeightDiffError = double.NaN; + + if (!double.IsNaN(sigma0)) + { + double q = 0.0; + + for (int row = 0; row < unknownCount; row++) + { + for (int column = 0; column < unknownCount; column++) + { + q += B[i, row] * Qxx[row, column] * B[i, column]; + } + } + + adjustedHeightDiffError = sigma0 * Math.Sqrt(Math.Abs(q)); + } result.Residuals.Add(residual); result.AdjustedHeightDiffs.Add(adjustedHeightDiff); @@ -218,7 +234,8 @@ namespace kcsj.Services Distance = obs.Distance, Weight = weights[i], Residual = residual, - AdjustedHeightDiff = adjustedHeightDiff + AdjustedHeightDiff = adjustedHeightDiff, + AdjustedHeightDiffError = adjustedHeightDiffError }); } @@ -239,4 +256,4 @@ namespace kcsj.Services return result; } } -} \ No newline at end of file +} diff --git a/Services/Report.cs b/Services/Report.cs index 7f20eb6..bc9ca94 100644 --- a/Services/Report.cs +++ b/Services/Report.cs @@ -1,12 +1,149 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Text; -using System.Threading.Tasks; +using kcsj.Models; namespace kcsj.Services { - internal class Report + public static class Report { + public static string BuildResultText(LeastSquaresResult result) + { + StringBuilder builder = new StringBuilder(); + + builder.AppendLine("========== 平差结果 =========="); + builder.AppendLine($"观测数:{result.ObservationCount}"); + builder.AppendLine($"未知点数:{result.UnknownCount}"); + builder.AppendLine($"多余观测数:{result.Redundancy}"); + builder.AppendLine($"单位权中误差:{FormatValue(result.Sigma0, 6)}"); + builder.AppendLine(); + + builder.AppendLine("一、未知点高程平差值"); + builder.AppendLine("点名\t平差高程(m)\t中误差(m)"); + foreach (KeyValuePair item in result.UnknownElevations) + { + double error = result.UnknownElevationErrors.TryGetValue(item.Key, out double value) + ? value + : double.NaN; + + builder.AppendLine($"{item.Key}\t{item.Value:F4}\t{FormatValue(error, 4)}"); + } + builder.AppendLine(); + + builder.AppendLine("二、高差平差值"); + builder.AppendLine("序号\t起点\t终点\t观测高差(m)\t改正数(m)\t平差后高差(m)\t中误差(m)"); + foreach (ObservationAdjustmentResult observationResult in result.ObservationResults) + { + builder.AppendLine( + $"{observationResult.Index}\t{observationResult.FromPoint}\t{observationResult.ToPoint}\t" + + $"{observationResult.ObservedHeightDiff:F6}\t{observationResult.Residual:F6}\t" + + $"{observationResult.AdjustedHeightDiff:F6}\t" + + $"{FormatValue(observationResult.AdjustedHeightDiffError, 6)}"); + } + + return builder.ToString(); + } + + public static string BuildHeightText(LeastSquaresResult result) + { + StringBuilder builder = new StringBuilder(); + + builder.AppendLine("点名\t高程平差值(m)\t中误差(m)"); + foreach (KeyValuePair item in result.UnknownElevations) + { + double error = result.UnknownElevationErrors.TryGetValue(item.Key, out double value) + ? value + : double.NaN; + + builder.AppendLine($"{item.Key}\t{item.Value:F4}\t{FormatValue(error, 4)}"); + } + + return builder.ToString(); + } + + public static string BuildSurveyText(LeastSquaresResult result) + { + StringBuilder builder = new StringBuilder(); + + builder.AppendLine("序号\t起点\t终点\t高差平差值(m)\t中误差(m)"); + foreach (ObservationAdjustmentResult observationResult in result.ObservationResults) + { + builder.AppendLine( + $"{observationResult.Index}\t{observationResult.FromPoint}\t{observationResult.ToPoint}\t" + + $"{observationResult.AdjustedHeightDiff:F6}\t" + + $"{FormatValue(observationResult.AdjustedHeightDiffError, 6)}"); + } + + return builder.ToString(); + } + + public static string BuildReportText( + IReadOnlyList knownPoints, + IReadOnlyList observations, + LeastSquaresResult result) + { + StringBuilder builder = new StringBuilder(); + + builder.AppendLine("水准网平差报告"); + builder.AppendLine($"生成时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}"); + builder.AppendLine(); + + builder.AppendLine("一、基本信息"); + builder.AppendLine($"数据来源:{DataStore.DataSource}"); + builder.AppendLine($"已知点数:{knownPoints.Count}"); + builder.AppendLine($"观测数:{result.ObservationCount}"); + builder.AppendLine($"未知点数:{result.UnknownCount}"); + builder.AppendLine($"多余观测数:{result.Redundancy}"); + builder.AppendLine($"单位权中误差:{FormatValue(result.Sigma0, 6)}"); + builder.AppendLine(); + + builder.AppendLine("二、已知点数据"); + builder.AppendLine("点名\t高程(m)"); + foreach (KnownPoint point in knownPoints) + { + builder.AppendLine($"{point.Name}\t{point.Elevation:F4}"); + } + builder.AppendLine(); + + builder.AppendLine("三、原始观测数据"); + builder.AppendLine("序号\t起点\t终点\t观测高差(m)\t距离(km)"); + for (int i = 0; i < observations.Count; i++) + { + Observation observation = observations[i]; + builder.AppendLine( + $"{i + 1}\t{observation.FromPoint}\t{observation.ToPoint}\t" + + $"{observation.HeightDiff:F6}\t{observation.Distance:F4}"); + } + builder.AppendLine(); + + builder.AppendLine("四、高程成果"); + builder.Append(BuildHeightText(result)); + builder.AppendLine(); + + builder.AppendLine("五、高差成果"); + builder.Append(BuildSurveyText(result)); + builder.AppendLine(); + + builder.AppendLine("六、观测改正数"); + builder.AppendLine("序号\t起点\t终点\t观测高差(m)\t改正数(m)\t平差后高差(m)\t距离(km)\t权"); + foreach (ObservationAdjustmentResult observationResult in result.ObservationResults) + { + builder.AppendLine( + $"{observationResult.Index}\t{observationResult.FromPoint}\t{observationResult.ToPoint}\t" + + $"{observationResult.ObservedHeightDiff:F6}\t{observationResult.Residual:F6}\t" + + $"{observationResult.AdjustedHeightDiff:F6}\t{observationResult.Distance:F4}\t" + + $"{observationResult.Weight:F6}"); + } + + return builder.ToString(); + } + + private static string FormatValue(double value, int digits) + { + if (double.IsNaN(value) || double.IsInfinity(value)) + { + return "无法计算"; + } + + return value.ToString($"F{digits}"); + } } }