using System;
using System.Linq;
class ClosedTraverseAdjustment
{
static void Main()
{
Console.WriteLine("闭合导线平差计算程序(完整修复版)");
Console.WriteLine("====================================");
// 输入控制点坐标
double x0 = ReadValue<double>("请输入起点X坐标(m): ");
double y0 = ReadValue<double>("请输入起点Y坐标(m): ");
// 输入导线参数
int n = ReadValue<int>("请输入导线边数: ");
if (n < 3)
{
Console.WriteLine("错误:导线边数必须大于等于3!");
return;
}
// 输入各边观测数据
double[] lengths = ReadArray(n, "边长(m): ", ReadValue<double>);
bool isLeftAngle = SelectAngleType();
double[] angles = ReadAngles(n, "观测角度(度分秒): ", isLeftAngle);
// 输入起始方位角
double alpha0 = ReadAngle("请输入起始坐标方位角(度分秒 格式: 度 分 秒): ");
// 角度闭合差计算
var angleClosure = CalculateAngleClosure(angles, n);
Console.WriteLine($"\n角度闭合差: {angleClosure.closure * 3600:F4}″");
Console.WriteLine($"理论总角度: {angleClosure.theoretical:F2}°, 实际总角度: {angleClosure.total:F2}°");
// 角度改正
double[] correctedAngles = CorrectAngles(angles, angleClosure.closure);
// 坐标方位角推算
double[] azimuths = CalculateAzimuths(alpha0, correctedAngles, isLeftAngle);
// 坐标增量计算
var deltas = CalculateDeltas(lengths, azimuths);
// 闭合差计算与分配
var closureErrors = CalculateClosureErrors(deltas.deltaX, deltas.deltaY);
var adjustedDeltas = AdjustDeltas(deltas.deltaX, deltas.deltaY, closureErrors.fx, closureErrors.fy, lengths);
// 坐标计算
var coordinates = CalculateCoordinates(x0, y0, adjustedDeltas.adjDeltaX, adjustedDeltas.adjDeltaY);
// 结果输出
PrintResults(correctedAngles, azimuths, adjustedDeltas, coordinates, closureErrors.fx, closureErrors.fy);
Console.WriteLine("\n计算完成!按任意键退出...");
Console.ReadKey();
}
#region 输入处理模块
static T ReadValue<T>(string prompt) where T : IConvertible
{
while (true)
{
try
{
Console.Write(prompt);
return (T)Convert.ChangeType(Console.ReadLine(), typeof(T));
}
catch
{
Console.Write($"输入错误,请重新输入{prompt}");
}
}
}
static T[] ReadArray<T>(int count, string basePrompt, Func<string, T> reader)
{
T[] array = new T[count];
for (int i = 0; i < count; i++)
{
string prompt = $"{basePrompt}{i + 1}: ";
array[i] = reader(prompt);
}
return array;
}
static double[] ReadAngles(int count, string basePrompt, bool isLeftAngle)
{
Console.WriteLine($"\n当前设置为{(isLeftAngle ? "左角" : "右角")}观测模式");
return ReadArray(count, basePrompt, (prompt) => ReadAngle(prompt));
}
static double ReadAngle(string prompt)
{
while (true)
{
try
{
Console.Write(prompt);
string[] parts = Console.ReadLine().Split(' ');
if (parts.Length != 3) throw new Exception("格式错误");
int deg = int.Parse(parts[0]);
int min = int.Parse(parts[1]);
double sec = double.Parse(parts[2]);
if (deg < 0 || deg >= 360 || min < 0 || min >= 60 || sec < 0 || sec >= 60)
throw new Exception("数值越界");
return deg + min / 60.0 + sec / 3600.0;
}
catch (Exception ex)
{
Console.WriteLine($"输入错误:{ex.Message}");
Console.WriteLine("请使用格式:度 分 秒(例如:123 30 45.5)");
}
}
}
static bool SelectAngleType()
{
while (true)
{
Console.Write("请选择角度类型 (1-右角/2-左角): ");
switch (Console.ReadLine())
{
case "1": return false;
case "2": return true;
default: Console.WriteLine("输入错误,请重新选择!"); break;
}
}
}
#endregion
#region 计算核心模块
static (double total, double theoretical, double closure) CalculateAngleClosure(double[] angles, int n)
{
double total = angles.Sum();
double theoretical = (n - 2) * 180;
return (total, theoretical, total - theoretical);
}
static double[] CorrectAngles(double[] angles, double closure)
{
double correction = closure / angles.Length;
for (int i = 0; i < angles.Length; i++)
{
angles[i] += correction;
}
return angles;
}
static double[] CalculateAzimuths(double startAzimuth, double[] angles, bool isLeftAngle)
{
double[] azimuths = new double[angles.Length];
azimuths[0] = startAzimuth;
for (int i = 1; i < angles.Length; i++)
{
azimuths[i] = azimuths[i - 1] +
(isLeftAngle ? 180 - angles[i - 1] : angles[i - 1] - 180);
azimuths[i] %= 360;
if (azimuths[i] < 0) azimuths[i] += 360;
}
return azimuths;
}
static (double[] deltaX, double[] deltaY) CalculateDeltas(double[] lengths, double[] azimuths)
{
double[] deltaX = new double[lengths.Length];
double[] deltaY = new double[lengths.Length];
for (int i = 0; i < lengths.Length; i++)
{
double rad = azimuths[i] * Math.PI / 180;
deltaX[i] = lengths[i] * Math.Cos(rad);
deltaY[i] = lengths[i] * Math.Sin(rad);
}
return (deltaX, deltaY);
}
static (double fx, double fy) CalculateClosureErrors(double[] deltaX, double[] deltaY)
{
if (deltaX.Length != deltaY.Length) throw new ArgumentException("输入数组长度不一致");
double sumX = deltaX.Sum();
double sumY = deltaY.Sum();
return (sumX, sumY);
}
static (double[] adjDeltaX, double[] adjDeltaY) AdjustDeltas(double[] deltaX, double[] deltaY, double fx, double fy, double[] lengths)
{
if (deltaX.Length != deltaY.Length || deltaX.Length != lengths.Length) throw new ArgumentException("输入数组长度不一致");
double totalLength = lengths.Sum();
double[] adjDeltaX = new double[deltaX.Length];
double[] adjDeltaY = new double[deltaY.Length];
for (int i = 0; i < deltaX.Length; i++)
{
adjDeltaX[i] = deltaX[i] - (fx * lengths[i] / totalLength);
adjDeltaY[i] = deltaY[i] - (fy * lengths[i] / totalLength);
}
return (adjDeltaX, adjDeltaY);
}
static (double[] x, double[] y) CalculateCoordinates(double x0, double y0, double[] deltaX, double[] deltaY)
{
if (deltaX.Length != deltaY.Length) throw new ArgumentException("输入数组长度不一致");
double[] x = new double[deltaX.Length + 1];
double[] y = new double[deltaY.Length + 1];
x[0] = x0;
y[0] = y0;
for (int i = 0; i < deltaX.Length; i++)
{
x[i + 1] = x[i] + deltaX[i];
y[i + 1] = y[i] + deltaY[i];
}
return (x, y);
}
#endregion
#region 结果输出模块
static void PrintResults(double[] angles, double[] azimuths, (double[] adjDeltaX, double[] adjDeltaY) deltas, (double[] x, double[] y) coordinates, double fx, double fy)
{
Console.Clear();
Console.WriteLine("计算结果:");
Console.WriteLine("====================================");
Console.WriteLine($"角度闭合差: {fx * 3600:F4}″(X方向), {fy * 3600:F4}″(Y方向)");
Console.WriteLine($"坐标增量闭合差: fx={fx:F4}m, fy={fy:F4}m\n");
PrintTable("改正后角度", "边号", "角度(°)", angles);
PrintTable("各边坐标方位角", "边号", "方位角(°)", azimuths);
PrintTable("改正后坐标增量", "边号", "ΔX(m)", "ΔY(m)", deltas.adjDeltaX, deltas.adjDeltaY);
PrintTable("各点坐标", "点号", "X(m)", "Y(m)", coordinates.x, coordinates.y);
}
static void PrintTable(string title, string col1, string col2, params double[][] data)
{
Console.WriteLine(title);
Console.WriteLine($"{col1}\t{col2}\t" + string.Join("\t", data.Select((_, i) => $"列{i + 3}")));
for (int i = 0; i < data[0].Length; i++)
{
Console.WriteLine($"{i + 1}\t{data[0][i]:F4}\t" + string.Join("\t", data.Skip(1).Select(d => d[i].ToString("F4"))));
}
Console.WriteLine();
}
#endregion
}