1,页面的设计
菜单,工具栏,表格
2,主界面的代码
主界面声明以下字段
public partial class Form1 : Form
{
public double H0;
public double L;
public double S;
public List<PointNew> I = new List<PointNew>();
public List<PointNew> All = new List<PointNew>();
public List<PointNew> K = new List<PointNew>();
public List<CenterPointcs> M = new List<CenterPointcs>();
导入数据到表格展示(在导入的时候就完成的全部计算main())
openFileDialog1.InitialDirectory = Directory.GetCurrentDirectory();
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string[][] data = File.ReadAllLines(openFileDialog1.FileName).Select(p => p.Split(',')).ToArray();
this.H0 = double.Parse(data[0][1]);
for (int i = 5; i < data.Length; i++)
{
if (data[i][0].Contains("K"))
{
K.Add(new PointNew(data[i]));
}
All.Add(new PointNew(data[i]));
this.dataGridView1.Rows.Add(data[i]);
}
MainC();
}
else
{
MessageBox.Show("取消");
return;
}
MessageBox.Show("读取成功");
}
总算法(这个命名其实不规范,Algorithm更规范)
public void MainC()
{
BasicFunction.KMileag(K);
L = K[K.Count - 1].mileage;
BasicFunction.Inster(All, K, ref S, ref I);
BasicFunction.CenterPointAlgorithm(K, All, ref M, H0);
}
3,类
新点类
构造一个新的点类
第四种构造函数的方便读取数据的
外带静态的计算距离的函数(加权计算高程时使用)
public class PointNew
{
public string ID;
public double X;
public double Y;
public double H;
public double mileage;
public PointNew()
{
}
public PointNew(double x,double y)
{
this.X = x;
this.Y = y;
}
public PointNew(double x, double y,double h)
{
this.X = x;
this.Y = y;
this.H = h;
}
public PointNew(string[]data)
{
this.ID = data[0];
this.X = double.Parse(data[1]);
this.Y= double.Parse(data[2]);
this.H= double.Parse(data[3]);
}
/// <summary>
/// 距离计算函数
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public double Distance(PointNew p2)
{
double dx = this.X - p2.X;
double dy = this.Y - p2.Y;
double distance = Math.Sqrt(dx * dx + dy * dy);
return distance;
}
中心点类(横断面的需要)
因为每个中心点都需要计算面积,所以设置以下字段方便计算
public class CenterPointcs:PointNew
{
public double S;//横断面的面积
public List<PointNew> points=new List<PointNew>();//断面上的点
public double K;//横断面的斜率
/// <summary>
/// 将中心点转换位PointNew形式,返回一个PointNew,不破坏原来的对象
/// </summary>
/// <returns></returns>
public PointNew ConvertToPointNew()
{
return new PointNew(this.X, this.Y, this.H);
}
}
IMPORTANT 计算的函数
加权计算高程的(使用sort或者orderby这个更方便但不是就地排序)
/// <summary>
/// 加权计算点的高程
/// </summary>
/// <param name="p1"></param>
/// <param name="ALl"></param>
public static void Hight(PointNew p1,List<PointNew>ALl)
{
//根据距离排序
List<PointNew> list= ALl.OrderBy(p => p.Distance(p1)).ToList();
//取前五个的元素的距离计算
double sum1 = list.Take(5).Sum(p => p.H / p.Distance(p1));
double sum2 = list.Take(5).Sum(p => 1 / p.Distance(p1));
p1.H = (sum1 / sum2);
}
初始化k点的里程的(后面可以直接用里程计算长度)
/// <summary>
/// 计算k点的里程
/// </summary>
/// <param name="K"></param>
public static void KMileag(List<PointNew>K)
{
K[0].mileage = 0;
double mileage = 0;
for (int i = 1; i <K.Count ; i++)
{
mileage+= K[i].Distance(K[i - 1]);
K[i].mileage = mileage;
}
}
两种断面的面积计算(写两个是因为偷懒,不想再计算横断面内插点的里程)
/// <summary>
/// 接收一段断面的点并且计算面积
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public static double Square(List<PointNew>p,double H)
{
double S = 0;
for (int i = 0; i < p.Count-1; i++)
{
S += (p[i].H + p[i + 1].H - 2 * H) * (p[i + 1].mileage - p[i].mileage) / 2;
}
return S;
}
/// <summary>
/// 接收一段横断面的点并且计算面积
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public static double Square2(List<PointNew> p, double H)
{
double S = 0;
for (int i = 0; i < p.Count - 1; i++)
{
S += (p[i].H + p[i + 1].H - 2 * H) * (5) / 2;
}
return S;
}
纵断面的内插点的计算
/// <summary>
/// 计算内插点坐标和高程
/// </summary>
/// <param name="ALL"></param>
/// <param name="K"></param>
/// <param name="S"></param>
public static void Inster(List<PointNew>ALL,List<PointNew>K,ref double S,ref List<PointNew>I )
{
//里程计数器
double L = 0;
S = 0;
for (int i = 0; i < K.Count-1; i++)
{
//计算方位角
double angle= Math.Atan2(K[i+1].Y - K[i].Y, K[i+1].X - K[i].X);
//计算内插个数
int num = (int)((K[i + 1].mileage - K[i].mileage) / 10);
//添加K点到内插点集合
I.Add(K[i]);
for (int k = 0; k < num; k++)
{
L += 10;
double detaL = L - K[i].mileage;//用增长的里程对K点的里程相减就可以获取detaL的长度
double X = K[i].X + detaL * Math.Cos(angle);
double Y = K[i].Y + detaL * Math.Sin(angle);
PointNew pointNew = new PointNew(X,Y);
BasicFunction.Hight(pointNew, ALL);
pointNew.mileage = L;
I.Add(pointNew);
}
}
I.Add(K[K.Count - 1]);
}
横断面的总算法
/// <summary>
/// 横断面的总算法
/// </summary>
/// <param name="K"></param>
/// <param name="ALl"></param>
/// <param name="M"></param>
public static void CenterPointAlgorithm(List<PointNew>K,List<PointNew>ALl,ref List<CenterPointcs>M,double H)
{
//计算中心点
for (int i = 0; i < K.Count-1; i++)
{
double X = K[i].X / 2 + K[i + 1].X/2;
double Y = K[i].Y / 2 + K[i + 1].Y / 2;
double k = Math.Atan2(K[i + 1].Y - K[i].Y, K[i + 1].X - K[i].X)+Math.PI/2;
if(k<0)//因为使用antan2可能返回负数
{
k += 2 * Math.PI;
}
CenterPointcs centerPointcs = new CenterPointcs();
centerPointcs.X = X;
centerPointcs.Y = Y;
Hight(centerPointcs, ALl);
M.Add(centerPointcs);
}
//计算横断面内插点
int L = -25;
for (int k = 0; k < M.Count; k++)
{
for (int i = 0; i < 10; i++)
{
if(i==5)//因为i=5时和中心点重复了
{
M[k].points.Add(M[k].ConvertToPointNew());
continue;
}
double detaL = L + i * 5;
double X = M[k].X + detaL * Math.Cos(M[k].K);
double Y = M[k].Y + detaL * Math.Sin(M[k].Y);
PointNew pointNew = new PointNew(X, Y);
Hight(pointNew,ALl);
M[k].points.Add(pointNew);
}
}
//计算面积
for (int i = 0; i < M.Count; i++)
{
M[i].S = Square2(M[i].points,H);
}
}
4,成果的展示
创建了两个窗体,需要的时候实例化显示数据
private void 纵断面内插点计算ToolStripMenuItem_Click(object sender, EventArgs e)
{
Report report = new Report();
report.Text = "内插点坐标";
report.richTextBox1.Text = "---------纵断面内插点(包含K点)----------\n";
report.richTextBox1.Text += "点号\t\tX\t\tY\t\tH\n";
for (int i = 0; i < I.Count; i++)
{
report.richTextBox1.Text += i.ToString() + "\t\t" + I[i].X.ToString("f3") + "\t\t" + I[i].Y.ToString("f3") + "\t\t" + I[i].H.ToString("f3") + "\n";
}
report.Show();
}
参考如下