Migrate desktop app to Avalonia and publish cross-platform releases
Build and Release / Publish Windows, Linux and macOS (push) Successful in 3m7s
Build and Release / Publish Windows, Linux and macOS (push) Successful in 3m7s
This commit is contained in:
@@ -71,10 +71,10 @@ namespace kcsj.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
CheckKnownPoints(knownPoints, result);
|
||||
CheckObservations(observations, result);
|
||||
CheckNetwork(knownPoints, observations, result);
|
||||
CheckRedundancy(knownPoints, observations, result);
|
||||
CheckKnownPoints(knownPoints!, result);
|
||||
CheckObservations(observations!, result);
|
||||
CheckNetwork(knownPoints!, observations!, result);
|
||||
CheckRedundancy(knownPoints!, observations!, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -293,4 +293,4 @@ namespace kcsj.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using kcsj.Models;
|
||||
|
||||
namespace kcsj.Services;
|
||||
|
||||
public static class InputParser
|
||||
{
|
||||
private static readonly char[] Separators = [' ', '\t', ',', ','];
|
||||
|
||||
public static List<KnownPoint> ReadKnownPointsFile(string filePath) =>
|
||||
ParseKnownPoints(File.ReadLines(filePath, Encoding.UTF8), Path.GetFileName(filePath));
|
||||
|
||||
public static List<Observation> ReadObservationsFile(string filePath) =>
|
||||
ParseObservations(File.ReadLines(filePath, Encoding.UTF8), Path.GetFileName(filePath));
|
||||
|
||||
public static List<KnownPoint> ParseKnownPointsText(string text) =>
|
||||
ParseKnownPoints(SplitText(text), "手动输入");
|
||||
|
||||
public static List<Observation> ParseObservationsText(string text) =>
|
||||
ParseObservations(SplitText(text), "手动输入");
|
||||
|
||||
public static string BuildKnownPointsPreview(IEnumerable<KnownPoint> points)
|
||||
{
|
||||
StringBuilder text = new("点名\t高程(m)\n");
|
||||
foreach (KnownPoint point in points)
|
||||
{
|
||||
text.AppendLine($"{point.Name}\t{point.Elevation:F4}");
|
||||
}
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
public static string BuildObservationsPreview(IEnumerable<Observation> observations)
|
||||
{
|
||||
StringBuilder text = new("起点\t终点\t高差(m)\t距离(km)\n");
|
||||
foreach (Observation observation in observations)
|
||||
{
|
||||
text.AppendLine(
|
||||
$"{observation.FromPoint}\t{observation.ToPoint}\t" +
|
||||
$"{observation.HeightDiff:F6}\t{observation.Distance:F4}");
|
||||
}
|
||||
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
private static List<KnownPoint> ParseKnownPoints(IEnumerable<string> lines, string sourceName)
|
||||
{
|
||||
List<KnownPoint> result = [];
|
||||
HashSet<string> names = new(StringComparer.OrdinalIgnoreCase);
|
||||
int lineNumber = 0;
|
||||
|
||||
foreach (string rawLine in lines)
|
||||
{
|
||||
lineNumber++;
|
||||
string line = rawLine.Trim();
|
||||
if (ShouldSkip(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] parts = SplitLine(line);
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行格式错误,应为:点名 高程");
|
||||
}
|
||||
|
||||
string name = parts[0].Trim();
|
||||
if (!names.Add(name))
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行点名重复:{name}");
|
||||
}
|
||||
|
||||
if (!TryParseNumber(parts[1], out double elevation))
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行高程不是有效数字");
|
||||
}
|
||||
|
||||
result.Add(new KnownPoint(name, elevation));
|
||||
}
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
throw new FormatException($"{sourceName} 中没有有效的已知点数据");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Observation> ParseObservations(IEnumerable<string> lines, string sourceName)
|
||||
{
|
||||
List<Observation> result = [];
|
||||
int lineNumber = 0;
|
||||
|
||||
foreach (string rawLine in lines)
|
||||
{
|
||||
lineNumber++;
|
||||
string line = rawLine.Trim();
|
||||
if (ShouldSkip(line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string[] parts = SplitLine(line);
|
||||
if (parts.Length != 4)
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行格式错误,应为:起点 终点 高差 距离");
|
||||
}
|
||||
|
||||
string from = parts[0].Trim();
|
||||
string to = parts[1].Trim();
|
||||
if (string.Equals(from, to, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行起点和终点不能相同");
|
||||
}
|
||||
|
||||
if (!TryParseNumber(parts[2], out double heightDiff))
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行高差不是有效数字");
|
||||
}
|
||||
|
||||
if (!TryParseNumber(parts[3], out double distance) || distance <= 0)
|
||||
{
|
||||
throw new FormatException($"{sourceName} 第 {lineNumber} 行距离必须是大于 0 的数字");
|
||||
}
|
||||
|
||||
result.Add(new Observation(from, to, heightDiff, distance));
|
||||
}
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
throw new FormatException($"{sourceName} 中没有有效的观测数据");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string[] SplitText(string text) =>
|
||||
text.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n').Split('\n');
|
||||
|
||||
private static string[] SplitLine(string line) =>
|
||||
line.Split(Separators, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
private static bool ShouldSkip(string line) =>
|
||||
string.IsNullOrWhiteSpace(line) || line.StartsWith('#') || line.StartsWith("//", StringComparison.Ordinal);
|
||||
|
||||
private static bool TryParseNumber(string text, out double value) =>
|
||||
double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value) ||
|
||||
double.TryParse(text, NumberStyles.Float, CultureInfo.CurrentCulture, out value);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace kcsj.Services
|
||||
{
|
||||
public static class LogService
|
||||
{
|
||||
public static event Action<string> OnLog;
|
||||
public static event Action<string>? OnLog;
|
||||
public static void AddLog(string message)
|
||||
{
|
||||
string time = DateTime.Now.ToString("HH:mm:ss");
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace kcsj.Services;
|
||||
|
||||
public static class PlatformLauncher
|
||||
{
|
||||
public static void OpenFolder(string folderPath)
|
||||
{
|
||||
ProcessStartInfo startInfo;
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = folderPath,
|
||||
UseShellExecute = true
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = OperatingSystem.IsMacOS() ? "open" : "xdg-open",
|
||||
UseShellExecute = false
|
||||
};
|
||||
startInfo.ArgumentList.Add(folderPath);
|
||||
}
|
||||
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user