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.
345 lines
13 KiB
C#
345 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using NaturalNeighbor;
|
|
|
|
namespace NeighborInterpolator
|
|
{
|
|
public class GridCreator
|
|
{
|
|
public GridCreator() { }
|
|
/// <summary>
|
|
/// 网格化生成图形.
|
|
/// </summary>
|
|
/// <param name="xyzFile">The xyz file.</param>
|
|
/// <param name="outputFile">The output file.</param>
|
|
/// <param name="borderFile">The border file.</param>
|
|
/// <param name="cols">The cols.</param>
|
|
/// <param name="rows">The rows.</param>
|
|
/// <param name="insertTimes">The insert times.</param>
|
|
/// <param name="contourStep">The contour step.</param>
|
|
/// <param name="contourMarkStep">The contour mark step.</param>
|
|
/// <returns></returns>
|
|
public bool Create(string xyzFile, string outputFile, string borderFile
|
|
, int cols, int rows
|
|
, int insertTimes, double contourStep, int contourMarkStep
|
|
, double xMin = -1.0, double yMin = -1.0, double xMax = -1.0, double yMax = -1.0)
|
|
{
|
|
// 读取数据,计算坐标范围
|
|
Vector3[] points = this.ReadData(xyzFile).ToArray();
|
|
Vector3 xyzMin = new Vector3();
|
|
Vector3 xyzMax = new Vector3();
|
|
this.CalculateRange(points, ref xyzMin, ref xyzMax);
|
|
|
|
Vector3 rangeMin = xyzMin;
|
|
Vector3 rangeMax = xyzMax;
|
|
|
|
Vector2 borderMin = new Vector2();
|
|
Vector2 borderMax = new Vector2();
|
|
Vector2[] borderData = null;
|
|
bool bHasBorder = !String.IsNullOrEmpty(borderFile) && File.Exists(borderFile);
|
|
if (bHasBorder)
|
|
{
|
|
borderData = ReadBorder(borderFile).ToArray();
|
|
if(borderData!=null && borderData.Count() > 0)
|
|
{
|
|
CalculateRange2D(borderData, ref borderMin, ref borderMax);
|
|
rangeMin.X = Math.Min(rangeMin.X, borderMin.X);
|
|
rangeMin.Y = Math.Min(rangeMin.Y, borderMin.Y);
|
|
|
|
rangeMax.X = Math.Max(rangeMax.X, borderMax.X);
|
|
rangeMax.Y = Math.Max(rangeMax.Y, borderMax.Y);
|
|
}
|
|
else
|
|
{
|
|
bHasBorder = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (xMin > 0 && yMin > 0)
|
|
{
|
|
rangeMin.X = Math.Min(rangeMin.X, (float)xMin);
|
|
rangeMin.Y = Math.Min(rangeMin.Y, (float)yMin);
|
|
|
|
rangeMax.X = Math.Max(rangeMax.X, (float)xMax);
|
|
rangeMax.Y = Math.Max(rangeMax.Y, (float)yMax);
|
|
|
|
borderData = new Vector2[5];
|
|
borderData[0] = new Vector2(rangeMin.X, rangeMin.Y);
|
|
borderData[1] = new Vector2(rangeMin.X, rangeMax.Y);
|
|
borderData[2] = new Vector2(rangeMax.X, rangeMax.Y);
|
|
borderData[3] = new Vector2(rangeMax.X, rangeMin.Y);
|
|
borderData[4] = new Vector2(rangeMin.X, rangeMin.Y);
|
|
|
|
CalculateRange2D(borderData, ref borderMin, ref borderMax);
|
|
|
|
bHasBorder = true;
|
|
}
|
|
}
|
|
|
|
double dExpand = 10;
|
|
if(rangeMin.X < xyzMin.X)
|
|
{
|
|
dExpand = xyzMin.X - rangeMin.X;
|
|
}
|
|
if (rangeMin.Y < xyzMin.Y)
|
|
{
|
|
dExpand = Math.Max(dExpand, xyzMin.Y - rangeMin.Y);
|
|
}
|
|
if (rangeMax.X> xyzMax.X)
|
|
{
|
|
dExpand = Math.Max(dExpand, rangeMax.X - xyzMax.X);
|
|
}
|
|
if (rangeMax.Y > xyzMax.Y)
|
|
{
|
|
dExpand = Math.Max(dExpand, rangeMax.Y - xyzMax.Y);
|
|
}
|
|
dExpand += 10;
|
|
|
|
// 处理为相对坐标
|
|
int nCount = points.Length;
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
points[i].X -= rangeMin.X;
|
|
points[i].Y -= rangeMin.Y;
|
|
}
|
|
Interpolator2d interpolator = Interpolator2d.Create(points.ToArray(), dExpand);
|
|
|
|
// 生成网格的大小
|
|
double dWidth = rangeMax.X - rangeMin.X;
|
|
double dHeight = rangeMax.Y - rangeMin.Y;
|
|
if (bHasBorder)
|
|
{
|
|
dWidth = borderMax.X - borderMin.X;
|
|
dHeight = borderMax.Y - borderMin.Y;
|
|
}
|
|
|
|
double scaleX = dWidth / (cols - 1);
|
|
double scaleY = dHeight / (rows - 1);
|
|
float dScale = (float)Math.Min(scaleX, scaleY);
|
|
|
|
int nCalCols = (int)Math.Ceiling(dWidth / dScale)+1;
|
|
int nCalRows = (int)Math.Ceiling(dHeight / dScale)+1;
|
|
// 构建网格节点
|
|
Vector2[] result = new Vector2[nCalRows * nCalCols];
|
|
double[] resultZ = new double[nCalRows * nCalCols];
|
|
for (int i = 0; i < nCalCols; ++i)
|
|
{
|
|
var x = i * dScale;
|
|
for (int j = 0; j < nCalRows; ++j)
|
|
{
|
|
var y = j * dScale;
|
|
result[i * nCalRows + j] = new Vector2(x, y);
|
|
//resultZ[i * nCalRows + j] = interpolator.Lookup(result[i * nCalRows + j]);
|
|
}
|
|
}
|
|
|
|
interpolator.LookupRange(result, resultZ);//, new ParallelOptions() { }
|
|
|
|
//string strResult = "C:\\GeoIntelligent\\Test\\厚度图数据\\40SO(300)-Result.csv";
|
|
//using (StreamWriter sw = new StreamWriter(strResult, false, Encoding.Default))
|
|
//{
|
|
// for (int i = 0; i < nCalCols; i++)
|
|
// {
|
|
// for (int j = 0; j < nCalRows; j++)
|
|
// {
|
|
// sw.WriteLine($"{i},{j},{resultZ[i * nCalRows + j]}");
|
|
// }
|
|
// }
|
|
//}
|
|
double[] daBorder = null;
|
|
if (bHasBorder)
|
|
{
|
|
daBorder = new double[borderData.Length * 2];
|
|
for (int i = 0; i < borderData.Length; i++)
|
|
{
|
|
daBorder[i * 2] = borderData[i].X;
|
|
daBorder[i * 2 + 1] = borderData[i].Y;
|
|
}
|
|
}
|
|
try
|
|
{
|
|
IntPtr pEvent = IntPtr.Zero;
|
|
//if (ProgressChanged != null)
|
|
//{
|
|
// pEvent = Marshal.GetFunctionPointerForDelegate(ProgressChanged);
|
|
//}
|
|
Thread newThread = new Thread(new ThreadStart(() =>
|
|
{
|
|
//SetDllDirectory(System.Windows.Forms.Application.StartupPath);
|
|
// 生成网格
|
|
SetGridData(rangeMin.X, rangeMin.Y, resultZ, nCalCols, nCalRows, (double)dScale, (double)dScale
|
|
, rangeMin.Z, rangeMax.Z, insertTimes, daBorder, daBorder == null ? 0 : daBorder.Length);
|
|
// 保存网格,同时生成等值线
|
|
SaveDrawFile(outputFile, contourStep, contourMarkStep);
|
|
DestoryXy();
|
|
}), 2621440);
|
|
newThread.Start();
|
|
newThread.Join();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Trace.WriteLine(ex.Message);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// 读取边界文件的数据.
|
|
/// </summary>
|
|
/// <param name="fileName">Name of the file.</param>
|
|
/// <returns></returns>
|
|
private IEnumerable<Vector2> ReadBorder(string fileName)
|
|
{
|
|
using (StreamReader rd = new StreamReader(File.Open(fileName, FileMode.Open), Encoding.Default))
|
|
{
|
|
string strLine = string.Empty;
|
|
while ((strLine = rd.ReadLine()) != null)
|
|
{
|
|
if (strLine.StartsWith("Pline.", StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while ((strLine = rd.ReadLine()) != null)
|
|
{
|
|
var parts = strLine.Split(',');
|
|
if (parts.Length >= 2 &&
|
|
float.TryParse(parts[0], out var x) &&
|
|
float.TryParse(parts[1], out var y))
|
|
{
|
|
yield return new Vector2((float)x, (float)y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 读取散点数据.
|
|
/// </summary>
|
|
/// <param name="filename">The filename.</param>
|
|
/// <returns></returns>
|
|
private IEnumerable<Vector3> ReadData(string filename)
|
|
{
|
|
using (StreamReader txt = new StreamReader(File.Open(filename, FileMode.Open), Encoding.Default))
|
|
{
|
|
txt.ReadLine(); // Skip columns
|
|
|
|
var s = txt.ReadLine();
|
|
while (s != null)
|
|
{
|
|
var parts = s.Split(',');
|
|
if (parts.Length >= 3 &&
|
|
float.TryParse(parts[0], out var x) &&
|
|
float.TryParse(parts[1], out var y) &&
|
|
float.TryParse(parts[2], out var z))
|
|
{
|
|
yield return new Vector3((float)x, (float)y, (float)z);
|
|
}
|
|
|
|
s = txt.ReadLine();
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 计算二维数据点的范围.
|
|
/// </summary>
|
|
/// <param name="points">The points.</param>
|
|
/// <param name="pointMin">The point minimum.</param>
|
|
/// <param name="pointMax">The point maximum.</param>
|
|
private void CalculateRange2D(Vector2[] points, ref Vector2 pointMin, ref Vector2 pointMax)
|
|
{
|
|
if (points.Length == 0)
|
|
{
|
|
pointMin = pointMax = Vector2.Zero;
|
|
return;
|
|
}
|
|
float minX = float.MaxValue;
|
|
float minY = float.MaxValue;
|
|
|
|
float maxX = float.MinValue;
|
|
float maxY = float.MinValue;
|
|
|
|
foreach (Vector2 pt in points)
|
|
{
|
|
minX = Math.Min(minX, pt.X);
|
|
maxX = Math.Max(maxX, pt.X);
|
|
|
|
minY = Math.Min(minY, pt.Y);
|
|
maxY = Math.Max(maxY, pt.Y);
|
|
}
|
|
pointMin.X = minX;
|
|
pointMin.Y = minY;
|
|
|
|
pointMax.X = maxX;
|
|
pointMax.Y = maxY;
|
|
|
|
}
|
|
/// <summary>
|
|
/// 计算坐标范围.
|
|
/// </summary>
|
|
/// <param name="points">The points.</param>
|
|
/// <param name="pointMin">The point minimum.</param>
|
|
/// <param name="pointMax">The point maximum.</param>
|
|
private void CalculateRange(Vector3[] points, ref Vector3 pointMin, ref Vector3 pointMax)
|
|
{
|
|
if (points.Length == 0)
|
|
{
|
|
pointMin = pointMax = Vector3.Zero;
|
|
return;
|
|
}
|
|
|
|
float minX = float.MaxValue;
|
|
float minY = float.MaxValue;
|
|
float minZ = float.MaxValue;
|
|
|
|
float maxX = float.MinValue;
|
|
float maxY = float.MinValue;
|
|
float maxZ = float.MinValue;
|
|
|
|
foreach (Vector3 pt in points)
|
|
{
|
|
minX = Math.Min(minX, pt.X);
|
|
maxX = Math.Max(maxX, pt.X);
|
|
|
|
minY = Math.Min(minY, pt.Y);
|
|
maxY = Math.Max(maxY, pt.Y);
|
|
|
|
minZ = Math.Min(minZ, pt.Z);
|
|
maxZ = Math.Max(maxZ, pt.Z);
|
|
}
|
|
pointMin.X = minX;
|
|
pointMin.Y = minY;
|
|
pointMin.Z = minZ;
|
|
|
|
pointMax.X = maxX;
|
|
pointMax.Y = maxY;
|
|
pointMax.Z = maxZ;
|
|
}
|
|
|
|
#if DEBUG
|
|
const string DLL_FILE = "GridUtility.dll";
|
|
#else
|
|
const string DLL_FILE = "GridUtility.dll";
|
|
#endif
|
|
[DllImport(DLL_FILE, EntryPoint = "SetGridData", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void SetGridData(double xMin, double yMin, double[] pDataZ
|
|
, double nCols, int nRows, double dx, double dy
|
|
, double zMin, double zMax, int insertTimes
|
|
, double[] borderData, int borderDataSize);
|
|
|
|
[DllImport(DLL_FILE, EntryPoint = "SaveDrawFile", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern bool SaveDrawFile(string outputFile, double contourStep, int contourMarkStep);
|
|
|
|
[DllImport(DLL_FILE, EntryPoint = "Destroy", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void DestoryXy();
|
|
}
|
|
}
|