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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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);
}
}
}