最后功能

This commit is contained in:
2026-06-16 12:57:08 +08:00 Unverified
parent 7767d52bb9
commit dc9ca11cec
6 changed files with 374 additions and 126 deletions
+4 -3
View File
@@ -102,6 +102,7 @@
button2.TabIndex = 4; button2.TabIndex = 4;
button2.Text = "查看结果"; button2.Text = "查看结果";
button2.UseVisualStyleBackColor = true; button2.UseVisualStyleBackColor = true;
button2.Click += button2_Click;
// //
// button3 // button3
// //
@@ -162,7 +163,7 @@
// //
ToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { ToolStripMenuItem, ToolStripMenuItem }); ToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { ToolStripMenuItem, ToolStripMenuItem });
ToolStripMenuItem.Name = "数据输入ToolStripMenuItem"; ToolStripMenuItem.Name = "数据输入ToolStripMenuItem";
ToolStripMenuItem.Size = new Size(270, 34); ToolStripMenuItem.Size = new Size(218, 34);
ToolStripMenuItem.Text = "数据输入"; ToolStripMenuItem.Text = "数据输入";
// //
// 从文件ToolStripMenuItem // 从文件ToolStripMenuItem
@@ -182,14 +183,14 @@
// 删除当前数据ToolStripMenuItem // 删除当前数据ToolStripMenuItem
// //
ToolStripMenuItem.Name = "删除当前数据ToolStripMenuItem"; ToolStripMenuItem.Name = "删除当前数据ToolStripMenuItem";
ToolStripMenuItem.Size = new Size(270, 34); ToolStripMenuItem.Size = new Size(218, 34);
ToolStripMenuItem.Text = "删除当前数据"; ToolStripMenuItem.Text = "删除当前数据";
ToolStripMenuItem.Click += ToolStripMenuItem_Click; ToolStripMenuItem.Click += ToolStripMenuItem_Click;
// //
// 数据检查ToolStripMenuItem // 数据检查ToolStripMenuItem
// //
ToolStripMenuItem.Name = "数据检查ToolStripMenuItem"; ToolStripMenuItem.Name = "数据检查ToolStripMenuItem";
ToolStripMenuItem.Size = new Size(270, 34); ToolStripMenuItem.Size = new Size(218, 34);
ToolStripMenuItem.Text = "数据检查"; ToolStripMenuItem.Text = "数据检查";
ToolStripMenuItem.Click += ToolStripMenuItem_Click; ToolStripMenuItem.Click += ToolStripMenuItem_Click;
// //
+168 -115
View File
@@ -1,37 +1,33 @@
using kcsj.Models; using kcsj.Models;
using kcsj.Services; using kcsj.Services;
using System; using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace kcsj.Forms namespace kcsj.Forms
{ {
public partial class MainForm : Form public partial class MainForm : Form
{ {
private LeastSquaresResult? lastResult;
public MainForm() public MainForm()
{ {
InitializeComponent(); InitializeComponent();
button3.Click += button3_Click;
} }
private void btnDataInput_Click(object sender, EventArgs e) private void btnDataInput_Click(object sender, EventArgs e)
{ {
DataInputForm form = new DataInputForm(); DataInputForm form = new DataInputForm();
form.ShowDialog(); form.ShowDialog();
lastResult = null;
} }
private void MainForm_Load(object sender, EventArgs e) private void MainForm_Load(object sender, EventArgs e)
{ {
LogService.OnLog += ShowLog; LogService.OnLog += ShowLog;
LogService.AddLog("程序启动成功。"); LogService.AddLog("程序启动成功。");
} }
private void ShowLog(string message) private void ShowLog(string message)
{ {
LOG.AppendText(message + "\r\n"); LOG.AppendText(message + "\r\n");
@@ -47,13 +43,14 @@ namespace kcsj.Forms
{ {
FileInputForm form = new FileInputForm(); FileInputForm form = new FileInputForm();
form.ShowDialog(); form.ShowDialog();
lastResult = null;
} }
private void ToolStripMenuItem_Click(object sender, EventArgs e) private void ToolStripMenuItem_Click(object sender, EventArgs e)
{ {
ManualInputForm form = new ManualInputForm(); ManualInputForm form = new ManualInputForm();
form.ShowDialog(); form.ShowDialog();
lastResult = null;
} }
private void ToolStripMenuItem_Click(object sender, EventArgs e) private void ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -63,123 +60,27 @@ namespace kcsj.Forms
private void ToolStripMenuItem_Click(object sender, EventArgs e) private void ToolStripMenuItem_Click(object sender, EventArgs e)
{ {
try RunAdjustment();
{
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);
}
} }
private void ToolStripMenuItem_Click(object sender, EventArgs e) private void ToolStripMenuItem_Click(object sender, EventArgs e)
{ {
ShowAdjustmentResult();
} }
private void ToolStripMenuItem_Click(object sender, EventArgs e) private void ToolStripMenuItem_Click(object sender, EventArgs e)
{ {
ExportReport();
} }
private void btnDataInspect_Click(object sender, EventArgs e) private void btnDataInspect_Click(object sender, EventArgs e)
{ {
DataCheckResult result = DataCheck.Check(DataStore.KnownPoints, DataStore.Observations); CheckData();
LogService.AddLog(result.ToLogText());
LogService.AddLog(Environment.NewLine);
if (!result.IsValid)
{
MessageBox.Show(
"数据检查未通过,请查看日志信息。",
"数据检查",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
MessageBox.Show(
"数据检查通过,可以进行平差计算。",
"数据检查",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
} }
private void btnStartAdjust_Click(object sender, EventArgs e) private void btnStartAdjust_Click(object sender, EventArgs e)
{ {
try RunAdjustment();
{
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);
}
} }
private void ToolStripMenuItem_Click(object sender, EventArgs e) private void ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -188,22 +89,36 @@ namespace kcsj.Forms
"确定要清空当前数据吗?", "确定要清空当前数据吗?",
"二次确认", "二次确认",
MessageBoxButtons.YesNo, MessageBoxButtons.YesNo,
MessageBoxIcon.Warning MessageBoxIcon.Warning);
);
if (result == DialogResult.Yes) if (result == DialogResult.Yes)
{ {
DataStore.Clear(); DataStore.Clear();
lastResult = null;
LogService.AddLog("当前数据已清空"); LogService.AddLog("当前数据已清空");
} }
else else
{ {
this.Close();
LogService.AddLog("用户取消清空数据"); LogService.AddLog("用户取消清空数据");
} }
} }
private void ToolStripMenuItem_Click(object sender, EventArgs e) 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); DataCheckResult result = DataCheck.Check(DataStore.KnownPoints, DataStore.Observations);
@@ -227,5 +142,143 @@ namespace kcsj.Forms
MessageBoxButtons.OK, MessageBoxButtons.OK,
MessageBoxIcon.Information); 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<string, double> 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}");
}
} }
} }
+35
View File
@@ -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);
}
}
}
+6 -1
View File
@@ -64,5 +64,10 @@ namespace kcsj.Models
/// 平差后高差 h + v /// 平差后高差 h + v
/// </summary> /// </summary>
public double AdjustedHeightDiff { get; set; } public double AdjustedHeightDiff { get; set; }
/// <summary>
/// 平差后高差中误差
/// </summary>
public double AdjustedHeightDiffError { get; set; }
} }
} }
+19 -2
View File
@@ -205,6 +205,22 @@ namespace kcsj.Services
double residual = V[i, 0]; double residual = V[i, 0];
double adjustedHeightDiff = obs.HeightDiff + residual; 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.Residuals.Add(residual);
result.AdjustedHeightDiffs.Add(adjustedHeightDiff); result.AdjustedHeightDiffs.Add(adjustedHeightDiff);
@@ -218,7 +234,8 @@ namespace kcsj.Services
Distance = obs.Distance, Distance = obs.Distance,
Weight = weights[i], Weight = weights[i],
Residual = residual, Residual = residual,
AdjustedHeightDiff = adjustedHeightDiff AdjustedHeightDiff = adjustedHeightDiff,
AdjustedHeightDiffError = adjustedHeightDiffError
}); });
} }
@@ -239,4 +256,4 @@ namespace kcsj.Services
return result; return result;
} }
} }
} }
+142 -5
View File
@@ -1,12 +1,149 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using kcsj.Models;
namespace kcsj.Services 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<string, double> 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<string, double> 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<KnownPoint> knownPoints,
IReadOnlyList<Observation> 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}");
}
} }
} }