using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using NeighborInterpolator; namespace Construction.BatchCreateMap { /// /// 网格化执行上下文,包含各算法执行所需的全部信息。 /// public class GridCreateContext { public GridCreateParameter Parameter { get; set; } public string InputFile { get; set; } public string OutputFile { get; set; } /// 边界文件路径,无边界时为 "NULL" public string OutlineFile { get; set; } /// 断层文件路径,无断层时为 "NULL" 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 ProcessIds { get; set; } public string GridModelExePath { get; set; } public string CurveModelExePath { get; set; } /// /// 网格化后处理回调。参数为实际使用的断层文件路径(可为 null)。 /// public Func RunPostProcessing { get; set; } public Action AppendFile { get; set; } } /// /// 网格化算法策略接口。 /// public interface IGridCreator { bool Execute(GridCreateContext ctx); } /// /// 根据算法类型返回对应的策略实例。 /// public static class GridCreatorFactory { private static readonly Dictionary _registry = new Dictionary { [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 { { "--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); } } }