You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
15 KiB
C#

1 month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using NeighborInterpolator;
namespace Construction.BatchCreateMap
{
/// <summary>
/// 网格化执行上下文,包含各算法执行所需的全部信息。
/// </summary>
public class GridCreateContext
{
public GridCreateParameter Parameter { get; set; }
public string InputFile { get; set; }
public string OutputFile { get; set; }
/// <summary>边界文件路径,无边界时为 "NULL"</summary>
public string OutlineFile { get; set; }
/// <summary>断层文件路径,无断层时为 "NULL"</summary>
public string FaultFile { get; set; }
public string CurveFile { get; set; }
public string DfgFile { get; set; }
public string OutputDir { get; set; }
public string FileName { get; set; }
public int Flag { get; set; }
public ProgressEvent ProgressChanged { get; set; }
public List<int> ProcessIds { get; set; }
public string GridModelExePath { get; set; }
public string CurveModelExePath { get; set; }
/// <summary>
/// 网格化后处理回调。参数为实际使用的断层文件路径(可为 null
/// </summary>
public Func<string, bool> RunPostProcessing { get; set; }
public Action<string, string> AppendFile { get; set; }
}
/// <summary>
/// 网格化算法策略接口。
/// </summary>
public interface IGridCreator
{
bool Execute(GridCreateContext ctx);
}
/// <summary>
/// 根据算法类型返回对应的策略实例。
/// </summary>
public static class GridCreatorFactory
{
private static readonly Dictionary<ModelCreateType, IGridCreator> _registry =
new Dictionary<ModelCreateType, IGridCreator>
{
[ModelCreateType.Curvature] = new CurvatureGridCreator(),
[ModelCreateType.IDM] = new IdwGridCreator(),
[ModelCreateType.NatureNeighbor] = new NatureNeighborGridCreator(),
[ModelCreateType.QuikGrid] = new QuikGridCreator(),
[ModelCreateType.GmtSplineGrid] = new GmtSplineGridCreator(),
};
private static readonly IGridCreator _defaultCreator = new MinTensionGridCreator();
public static IGridCreator Get(ModelCreateType type) =>
_registry.TryGetValue(type, out var creator) ? creator : _defaultCreator;
}
// ─────────────────────────────────────────────────────────────────────────
// 内部辅助
// ─────────────────────────────────────────────────────────────────────────
internal static class NativeMethods
{
[DllImport("kernel32.dll")]
internal static extern uint GetCurrentThreadId();
}
// ─────────────────────────────────────────────────────────────────────────
// 最小曲率法 —— 调用外部进程 SurfaceGrid.exe
// ─────────────────────────────────────────────────────────────────────────
internal class CurvatureGridCreator : IGridCreator
{
public bool Execute(GridCreateContext ctx)
{
var para = ctx.Parameter;
var dic = new Dictionary<string, object>
{
{ "--source-point-file", $"\"{ctx.InputFile}\"" },
{ "--fault", $"\"{ctx.FaultFile}\"" },
{ "--breakline", $"\"{ctx.OutlineFile}\"" },
{ "--x-nodes-count", (ulong)para.M },
{ "--max-iteration", -1 },
{ "--residual", 0.0001 },
{ "--fill-value", 0.0 },
{ "--fault-edge-level", 0 },
{ "--output-file", $"\"{ctx.CurveFile}\"" },
{ "--estimate-factor", 0 },
{ "--corner-weight", 64 },
{ "--contour-step", para.CurveSpace },
{ "--contour-mark-step", para.LableSpace },
{ "--insert-times", para.Times },
{ "--smooth-times", para.Smooth },
{ "--area", $"{para.XMin},{para.YMin},{para.XMax},{para.YMax}" },
};
string strParameter = string.Join(" ", dic.Select(x => $"{x.Key} {x.Value}"));
Process p = new Process();
p.StartInfo.FileName = "SurfaceGrid.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = false;
p.StartInfo.RedirectStandardOutput = false;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = strParameter;
p.Start();
ctx.ProcessIds.Add(p.Id);
p.WaitForExit();
p.Close();
return ctx.RunPostProcessing(ctx.FaultFile);
}
}
// ─────────────────────────────────────────────────────────────────────────
// 反距离加权法 —— 在独立线程中调用 ModelCreateIDW
// ─────────────────────────────────────────────────────────────────────────
internal class IdwGridCreator : IGridCreator
{
public bool Execute(GridCreateContext ctx)
{
var para = ctx.Parameter;
IntPtr pEvent = IntPtr.Zero;
if (ctx.ProgressChanged != null)
{
pEvent = Marshal.GetFunctionPointerForDelegate(ctx.ProgressChanged);
}
bool bResult = false;
LayerCreate.ProcessThread = new Thread(new ThreadStart(() =>
{
LayerCreate.ProcessThreadId = NativeMethods.GetCurrentThreadId();
try
{
ModelCreateIDW.IDWModelCreate(
ctx.InputFile, ctx.OutlineFile, ctx.FaultFile, ctx.CurveFile,
para.M, para.Smooth, 3, pEvent, para.Times, para.CurveSpace, para.LableSpace,
para.XMin, para.YMin, para.XMax, para.YMax);
bResult = ctx.RunPostProcessing(ctx.FaultFile);
}
catch (ThreadAbortException)
{
bResult = false;
}
}), 2621440);
LayerCreate.ProcessThread.Start();
LayerCreate.ProcessThread.Join();
return bResult;
}
}
// ─────────────────────────────────────────────────────────────────────────
// 自然临近法 —— 在独立线程中调用 GridCreator
// ─────────────────────────────────────────────────────────────────────────
internal class NatureNeighborGridCreator : IGridCreator
{
public bool Execute(GridCreateContext ctx)
{
var para = ctx.Parameter;
bool bResult = false;
LayerCreate.ProcessThread = new Thread(new ThreadStart(() =>
{
LayerCreate.ProcessThreadId = NativeMethods.GetCurrentThreadId();
try
{
GridCreator creater = new GridCreator();
creater.Create(
ctx.InputFile, ctx.CurveFile, ctx.OutlineFile,
para.M, para.N, para.Times, para.CurveSpace, para.LableSpace,
para.XMin, para.YMin, para.XMax, para.YMax);
bResult = ctx.RunPostProcessing(ctx.FaultFile);
}
catch (ThreadAbortException)
{
bResult = false;
}
}));
LayerCreate.ProcessThread.Start();
LayerCreate.ProcessThread.Join();
return bResult;
}
}
// ─────────────────────────────────────────────────────────────────────────
// 快速网格化 —— 调用 QuikGridCS
// ─────────────────────────────────────────────────────────────────────────
internal class QuikGridCreator : IGridCreator
{
public bool Execute(GridCreateContext ctx)
{
var para = ctx.Parameter;
return QuikGridCS.Interface.QuikGridCreate(
ctx.InputFile, ctx.CurveFile,
para.M, para.N, para.CurveSpace, para.LableSpace, para.Smooth);
}
}
// ─────────────────────────────────────────────────────────────────────────
// 样条插值法 —— 调用外部进程 GmtSurfaceGrid.exe
// ─────────────────────────────────────────────────────────────────────────
internal class GmtSplineGridCreator : IGridCreator
{
public bool Execute(GridCreateContext ctx)
{
var para = ctx.Parameter;
string strOutputFile = $"{ctx.OutputDir}{ctx.FileName}.grd";
string strParameter = string.Format(
"\"{0}\" \"{1}\" \"{2}\" \"{3}\" \"{4}\" {5} {6} {7} {8} {9} {10} {11} {12}",
ctx.InputFile, strOutputFile, ctx.FaultFile,
ctx.OutlineFile, ctx.CurveFile, para.XStep,
0, para.CurveSpace, para.LableSpace,
para.XMin, para.YMin, para.XMax, para.YMax);
string exeDir = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string exeFilePath = System.IO.Path.Combine(exeDir, "GmtSurfaceGrid.exe");
Trace.WriteLine(strParameter);
Process p = new Process();
p.StartInfo.FileName = exeFilePath;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = strParameter;
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
int exitCode = p.ExitCode;
p.Close();
return exitCode == 0;
}
}
// ─────────────────────────────────────────────────────────────────────────
// 最小张力法(默认) —— 依次调用 GridModel.exe 和 CurveModel.exe
// ─────────────────────────────────────────────────────────────────────────
internal class MinTensionGridCreator : IGridCreator
{
public bool Execute(GridCreateContext ctx)
{
var para = ctx.Parameter;
string strParameter;
if (ctx.OutlineFile.Equals("NULL", StringComparison.CurrentCultureIgnoreCase))
{
strParameter = string.Format(
"\"{0}\" \"{1}\" {2} \"{3}\" \"{4}\" {5} {6} {7} {8} {9} {10} {11}",
ctx.InputFile, ctx.OutputFile, para.Times,
ctx.OutlineFile, ctx.FaultFile,
para.M, para.Smooth, 0,
para.XMin, para.YMin, para.XMax, para.YMax);
}
else
{
strParameter = string.Format(
"\"{0}\" \"{1}\" {2} \"{3}\" \"{4}\" {5} {6} {7}",
ctx.InputFile, ctx.OutputFile, para.Times,
ctx.OutlineFile, ctx.FaultFile,
para.M, para.Smooth, 0);
}
Trace.WriteLine(strParameter);
Process p = new Process();
p.StartInfo.FileName = ctx.GridModelExePath;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = false;
p.StartInfo.RedirectStandardOutput = false;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = strParameter;
p.Start();
p.WaitForExit();
p.Close();
if (ctx.Flag >= 3) return true;
// 生成等值线
// 原始逻辑faultFile 为 "NULL" 时置为 null后续传入 processAfterGrid
string faultFile = ctx.FaultFile.Equals("NULL") ? null : ctx.FaultFile;
string strCurveParameter = $"\"{ctx.OutputFile}\" \"{ctx.CurveFile}\"";
if (faultFile != null && faultFile.Length > 0)
{
strCurveParameter += $" \"{faultFile}\" {para.CurveSpace}";
}
else
{
strCurveParameter += $" NULL {para.CurveSpace}";
}
if (para.LableSpace > 0)
{
strCurveParameter += $" {para.LableSpace}";
}
Trace.WriteLine(strCurveParameter);
p = new Process();
p.StartInfo.FileName = ctx.CurveModelExePath;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = false;
p.StartInfo.RedirectStandardOutput = false;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = strCurveParameter;
p.Start();
p.WaitForExit();
p.Close();
if (faultFile != null && faultFile.Length > 0)
ctx.AppendFile(ctx.CurveFile, faultFile);
return ctx.RunPostProcessing(faultFile);
}
}
}