UI设计(仅供参考)
用到的控件;
菜单栏,标签,列表,表格,tab容器,文本框,richbox,表格,图表。
在主界面放需要的初始变量;
public int number;//未知点个数
public List<PointF> points = new List<PointF>();//点的坐标
public List<double> length= new List<Double>();//边长
public List<double> angle = new List<Double>();//角度
public string angle_type;//角度类型
public string lenhth_type; //导线类型
public bool model=false; //手写模式是否打开
导入文件(需要写xls和txt两种格式);
我们先先封装好两个方法,它们接收文件路径。
excel的读取
public void excel(string filename)//读取excel文件
{
Microsoft.Office.Interop.Excel.Application xlsApp = new Microsoft.Office.Interop.Excel.Application(); // Excel程序对象
Microsoft.Office.Interop.Excel.Workbook Wb = null; // Exce 工作簿对象
Microsoft.Office.Interop.Excel.Worksheet WSheet = null; // Exce工作表对象
xlsApp.Visible = false; // Excel程序对象界面不可见
xlsApp.DisplayAlerts = true; // 不显示系统提示
Wb = xlsApp.Workbooks.Open(filename); // 打开Excel文件
WSheet = Wb.Sheets[1]; // 指定工作表
int XStart = 0;
int XEnd = 0;
//遍历所有有效行获取数据
for(int i=1;i<=WSheet.UsedRange.Rows.Count;i++)
{
//获取当前遍历行的值
string value =(string) WSheet.Cells[i,1].Value;
if(value== "已知点信息")//
{
//获取坐标起始行
XStart= i;
}
if (value == "夹角类型")//
{
//获取坐标结束行
XEnd= i;
break;
}
}
//开始赋值
this.lenhth_type = WSheet.Cells[XStart - 1, 2].Value;//导线类型
this.angle_type = WSheet.Cells[XEnd, 2].Value;//观测角类型
this.angle_type = this.angle_type == "左角" ? "1" : "2";
this.lenhth_type = this.lenhth_type == "附和导线" ? "1" : "2";
//坐标获取
//获取坐标有效行数
int hang = XEnd - XStart - 2;
for (int i = 0; i < hang; i++)
{
float temp_x = (float)WSheet.Cells[XStart+2+i,2].Value;
float temp_y = (float)WSheet.Cells[XStart + 2+i, 3].Value;
PointF n1=new PointF(temp_x, temp_y);
this.points.Add(n1);
}
//获取角度有效行数
int hang_angle = WSheet.UsedRange.Rows.Count - XEnd -4;
//获取未知点个数
this.number =hang_angle-2;
for (int i=0;i<hang_angle;i++)
{
angle.Add(WSheet.Cells[XEnd+4+i,2].Value);
}
for (int i = 0; i < hang_angle-1; i++)
{
length.Add(WSheet.Cells[XEnd + 5 + i, 3].Value);
}
}
我们遍历有效行,获取“有已知点信息”,“夹角类型”,作为相对位置求出其他数据的位置。
以闭合导线的xls文件为参考,求出”已知点信息“这一列的位置就可以知道其他的信息。
已知点坐标的有效行数是;
int hang = XEnd - XStart - 2;
以此类推;
txt文本的读取;
public void txt(string filename)//读取txt文件
{
string[] data;
data = File.ReadAllLines(filename, Encoding.Default);
for (int i = 0; i < data.Length; i++)
{
if (data[i].Contains("数据"))
{
int key = i;//获取开始的行
this.lenhth_type = data[i + 1];
this.angle_type = data[i + 2];
//读取已知点坐标
float[] po = Array.ConvertAll(data[i + 4].Split(','), float.Parse);
for (int j = 0; j < po.Length - 1; j += 2)
{
PointF temp = new PointF(po[j], po[j + 1]);
this.points.Add(temp);
}
//分别给角度,长度赋值
this.angle_type = data[i + 5];
this.number = angle.Count - 2;
this.angle = Array.ConvertAll(data[i + 6].Split(','), double.Parse).ToList();
this.length = Array.ConvertAll(data[i + 7].Split(','), double.Parse).ToList();
}
}
}
这里我们用cotains方法判断从哪里开始读取数据,然后切割存储,没什么难度。
数据的展示;
private void 文件ToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "文本文件(*.txt)|*.txt|Excel表格文件(*.xls)|*.xls";
openFileDialog.InitialDirectory = @"C:\";
openFileDialog.Title = "Select a Text File";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
//ToloWer是转小写的方法
string fileName = openFileDialog.FileName;
if (fileName.ToLower().Contains(".txt"))
txt(fileName); // 从文本文件中导入数据
if (fileName.ToLower().Contains(".xls"))
excel(fileName); // 从XLS文件中导入数据
//把数据打印在列表里面
dataGridView1.Rows.Add();
inster_data(lenhth_type);
for (int i = 0; i <this.angle.Count; i++)
{
dataGridView1.Rows.Add();
dataGridView1.Rows[i].Cells[0].Value = angle[i];
}
for (int i = 0; i < this.length.Count; i++)
{
dataGridView1.Rows.Add();
dataGridView1.Rows[i].Cells[1].Value = length[i];
}
//给listbox的选项赋值
if (this.lenhth_type== "1")
{
this.listBox1.SelectedIndex= 0;
}
else { this.listBox1.SelectedIndex = 1; ; }
if (this.angle_type == "1")
{
this.listBox2.SelectedIndex = 0;
}
else { this.listBox2.SelectedIndex = 1; }
}
catch (Exception ex)
{
MessageBox.Show("An error occurred: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("导入失败");
return;
}
}
给文本框赋值;
public void inster_data(string type)//初始化表格数据
{
if (type == "1")
{
textBox1.Text = Convert.ToString(points[0].X);
this.textBox2.Text=Convert.ToString(points[0].Y);
this.textBox3.Text= Convert.ToString(points[1].X);
this.textBox4.Text= Convert.ToString(points[1].Y);
this.textBox5.Text= Convert.ToString(points[2].X);
this.textBox6.Text= Convert.ToString(points[2].Y);
this.textBox7.Text= Convert.ToString(points[3].X);
this.textBox8.Text= Convert.ToString(points[3].Y);
}
else
{
textBox1.Text = Convert.ToString(points[0].X);
this.textBox2.Text = Convert.ToString(points[0].Y);
this.textBox3.Text = Convert.ToString(points[1].X);
this.textBox4.Text = Convert.ToString(points[1].Y);
}
}
手写和导入模式的切换;
我们开头已经设置的一个bool值,默认false为导入模式。
private void 切换模式手写ToolStripMenuItem_Click(object sender, EventArgs e)
{
if(model==false)
{
textBox1.Enabled = true;
this.textBox2.Enabled = true;
this.textBox3.Enabled = true;
this.textBox4.Enabled = true;
this.textBox5.Enabled = true;
this.textBox6.Enabled = true;
this.textBox7.Enabled = true;
this.textBox8.Enabled = true;
this.dataGridView1.Enabled = true;
model= true;
this.label7.Text = "手写模式";
}
else {
textBox1.Enabled = false;
this.textBox2.Enabled = false;
this.textBox3.Enabled = false;
this.textBox4.Enabled = false;
this.textBox5.Enabled = false;
this.textBox6.Enabled = false;
this.textBox7.Enabled = false;
this.textBox8.Enabled = false;
this.dataGridView1.Enabled = false;
model= false;
this.label7.Text = "读取模式";
}
}
不建议这样写,可以把这些控件放在一个大的控件块上,修改控件块的enabled属性即可。
但是我懒得改了。
算法部分
我们新建一个cs文件。将方法封装在里面。
并且设置以下需要用到的字段;
public string angle_type;
public string length_type;
public int n;//未知点个数
List<double> angle = new List<double>(); //角度
List<double> length = new List<double>(); //长度
List<double> calculateBearing = new List<double>(); //坐标方位角
List<double> calculateBearing_rapir = new List<double>(); //修正后坐标方位角
List<double> X = new List<double>(); //近似坐标X
List<double> Y = new List<double>(); //近似坐标Y
List<double> XRapir = new List<double>(); //修正X
List<double> YRapir = new List<double>(); //修正Y
double angle_start;//起始方位角
double angle_end;//结束方位角
double f_angle;//方位角闭合差
double f_x;
double f_y;
double f_s;
用到的基础函数;
1.坐标方位角的计算
public static double CalculateBearing(double x1, double y1, double x2, double y2)
{
double dx = x2 - x1;
double dy = y2 - y1;
double angle = Math.Atan(dy / dx);
if (dx < 0 && dy > 0) { angle += Math.PI; }
else if (dx < 0 && dy < 0) { angle += Math.PI; }
else if (dx > 0 && dy < 0) { angle += 2 * Math.PI; }
return angle;//这是弧度
}
2,ddmmss格式转弧度
// DMS转弧度
public static double DMS2Hu(double dms)
{
int d, m;
double s;
d = (int)Math.Floor(dms);
m = (int)Math.Floor((dms - d) * 100);
s = ((dms - d) * 100 - m) * 100;
double val;
val = (d + m / 60.0 + s / 3600.0) * Math.PI / 180;
return val;
}
3,ddmmss转角度
//ddmmss转换为角度
public static double ConvertToDegree(double coordinate1)
{
string coordinate = Convert.ToString(coordinate1);
int index= coordinate.IndexOf('.');
double du = Convert.ToDouble(coordinate.Substring(0, index));
double fen = Convert.ToDouble(coordinate.Substring(index+1, 2));
double miao = Convert.ToDouble(coordinate.Substring(index+2, 2));
double degree = (fen / 60);
double minutes = miao / 3600;
return du + degree + minutes;
}
我们设置一个主函数计算
public void main(Form1 form1,RichTextBox rich)//将主界面的对象和文本框传过来
{
//从表格和文本框获取数据
//计算起始和终止方位角
//计算近似方位角
//计算方位角闭合差
//分配方位角闭合差(注意迭代上一个闭合差)
//计算近似坐标
//计算平差后的坐标
//输出在界面的文本框
}
1.我们先获取表格和文本框数据
注意需要讲角度(ddmmss格式)转化为弧度
//获取表格数据
//边长
foreach (DataGridViewRow row in form1.dataGridView1.Rows)
{
if (!row.IsNewRow) // 排除新行
{
if(row.Cells[0].Value==null)
{ continue; }
angle.Add( Convert.ToDouble(row.Cells[0].Value)); // 获取第一列数据,并添加到 List 中
}
}
for(int i=0; i<angle.Count; i++) { angle[i] =DMS2Hu( angle[i]); }
foreach (DataGridViewRow row in form1.dataGridView1.Rows)
{
if (!row.IsNewRow) // 排除新行
{
if (row.Cells[0].Value == null)
{ continue; }
length.Add(Convert.ToDouble(row.Cells[1].Value)); // 获取第一列数据,并添加到 List 中
}
}
this.n = length.Count-1;//未知点个数
//获取类型
this.angle_type= form1.listBox2.SelectedItem.ToString();
this.length_type = form1.listBox1.SelectedItem.ToString();
2,根据文本框内容计算起始和终止方位角
//计算起终方位角
if (length_type == "附和")
{
angle_start = CalculateBearing(Convert.ToDouble(form1.textBox1.Text), Convert.ToDouble(form1.textBox2.Text), Convert.ToDouble(form1.textBox3.Text), Convert.ToDouble(form1.textBox4.Text));
angle_end = CalculateBearing(Convert.ToDouble(form1.textBox5.Text), Convert.ToDouble(form1.textBox6.Text), Convert.ToDouble(form1.textBox7.Text), Convert.ToDouble(form1.textBox8.Text));
}
else
{
angle_start = CalculateBearing(Convert.ToDouble(form1.textBox1.Text), Convert.ToDouble(form1.textBox2.Text), Convert.ToDouble(form1.textBox3.Text), Convert.ToDouble(form1.textBox4.Text));
angle_end = Math.PI + angle_start;
}
ps(闭合导线的终止角等于起始角加180度)
3.近似方位角的计算;
public void angle_zhe()//遍历角度计算坐标方位角
{
if (length_type == "附和")
{
if (angle_type == "左角")//左角
{
double temp = angle_start;
foreach (double x in angle)
{
temp = temp + x- Math.PI;
this.calculateBearing.Add(temp);
}
}
else//右角
{
int i = 0;
double temp = angle_start;
foreach (double x in angle)
{
temp = temp - x + Math.PI;
temp = temp > 2 * Math.PI ? temp - 2 * Math.PI : temp;
temp = temp > 2 * Math.PI ? temp - 2 * Math.PI : temp;//判断是否大于360度,最多720度。判断两次
this.calculateBearing.Add(temp);
}
}
}
else
{
double temp = angle_start;
if (angle_type == "左角")//左角
{
//针对闭合切左角的情况需要对第一个角和最后一个进行改正
angle[0] = 2 * Math.PI - angle[0];
angle[angle.Count - 1] = angle[angle.Count - 1] + (2 * Math.PI - angle[0]);
}
for (int j = 0; j < angle.Count; j++)
{
temp = temp - angle[j] - Math.PI;
if (temp > 2 * Math.PI)
{ temp -= 2 * Math.PI; }
if (temp <0)
{ temp += 2 * Math.PI; }
if (temp < 0)
{ temp += 2 * Math.PI; }
this.calculateBearing.Add(temp);
}
}
}
ps(闭合导线计算方法需要注意)。
4.计算角度闭合差
public void Closure_error_angle()//计算角度闭合差
{
this.f_angle = calculateBearing[calculateBearing.Count - 1] - angle_end;
}
5.计算是否超限
public void limt()//计算是否超限
{
}
不想写了。参考书p150页即可。
6.更新修正方位角
public void upadat_angle()//更新方位角
{
int i = 1;
double fb_ex = -this.f_angle / n;//闭合的均值
foreach(double a in this.calculateBearing ) { calculateBearing_rapir.Add(a+i*fb_ex); i++; }
}
7.计算坐标(注意迭代上一个值)
public void Corrding(Form1 form1)//计算坐标增量和闭合差
{
//获取起始点坐标
double x = Convert.ToDouble((form1.textBox3.Text));
double y = Convert.ToDouble((form1.textBox4.Text));
for (int i=0;i<form1.length.Count;i++)
{
x = (x + length[i] * Math.Cos(calculateBearing_rapir[i]));
X.Add(x);
y = (y + length[i] * Math.Sin(calculateBearing_rapir[i]));
Y.Add(y);
}
//计算坐标闭合差
if(length_type=="闭合导线")
{
f_x = X[X.Count-1]-Convert.ToDouble( form1.textBox5.Text);
f_y = Y[Y.Count - 1] - Convert.ToDouble(form1.textBox6.Text);
}
else
{
f_x = X[X.Count - 1] - Convert.ToDouble(form1.textBox3.Text);
f_y = Y[Y.Count - 1] - Convert.ToDouble(form1.textBox4.Text);
}
double vx =0;
double vy = 0;
//分配并且计算坐标
for (int i=0;i<X.Count;i++)
{
vx += -f_x * length[i] / length.Sum();
vy += -f_y * length[i] / length.Sum();
double temp = X[i] + vx;
double temp2 = Y[i] + vy;
XRapir.Add(temp);
YRapir.Add(temp2);
}
}
Last,主函数就是这样的。
public void main(Form1 form1,RichTextBox rich, System.Windows.Forms.DataVisualization.Charting.Chart chart)
{
//获取表格数据
//边长
foreach (DataGridViewRow row in form1.dataGridView1.Rows)
{
if (!row.IsNewRow) // 排除新行
{
if(row.Cells[0].Value==null)
{ continue; }
angle.Add( Convert.ToDouble(row.Cells[0].Value)); // 获取第一列数据,并添加到 List 中
}
}
for(int i=0; i<angle.Count; i++) { angle[i] =DMS2Hu( angle[i]); }
foreach (DataGridViewRow row in form1.dataGridView1.Rows)
{
if (!row.IsNewRow) // 排除新行
{
if (row.Cells[1].Value == null)
{ continue; }
length.Add(Convert.ToDouble(row.Cells[1].Value)); // 获取第一列数据,并添加到 List 中
}
}
this.n = length.Count-1;//未知点个数
//获取类型
this.angle_type= form1.listBox2.SelectedItem.ToString();
this.length_type = form1.listBox1.SelectedItem.ToString();
//计算起终方位角
if (length_type == "附和")
{
angle_start = CalculateBearing(Convert.ToDouble(form1.textBox1.Text), Convert.ToDouble(form1.textBox2.Text), Convert.ToDouble(form1.textBox3.Text), Convert.ToDouble(form1.textBox4.Text));
angle_end = CalculateBearing(Convert.ToDouble(form1.textBox5.Text), Convert.ToDouble(form1.textBox6.Text), Convert.ToDouble(form1.textBox7.Text), Convert.ToDouble(form1.textBox8.Text));
}
else
{
angle_start = CalculateBearing(Convert.ToDouble(form1.textBox1.Text), Convert.ToDouble(form1.textBox2.Text), Convert.ToDouble(form1.textBox3.Text), Convert.ToDouble(form1.textBox4.Text));
angle_end = Math.PI + angle_start;
}
angle_zhe();
calculateBearing.ForEach(n1 => rich.Text += (n1 * 180 / Math.PI).ToString("f4") + "\n");
Closure_error_angle();
calculateBearing_rapir.ForEach(n1 => rich.Text += (n1 * 180 / Math.PI).ToString("f4") + "\n");
upadat_angle();
Corrding(form1);
rich.Text = "未知点个数;" + n + "\n";
rich.Text += "起始方位角是;" + angle_start * 180 / Math.PI + "\n";
rich.Text += "终止方位角是;" + angle_end * 180 / Math.PI + "\n";
rich.Text += "近似方位角是;" + "\n";
for(int i=0;i<calculateBearing.Count;i++)
{ rich.Text += (calculateBearing[i] * 180 / Math.PI).ToString("f4") + "\n"; }
rich.Text += "改正方位角是;" + "\n";
for (int i = 0; i < calculateBearing_rapir.Count; i++)
{ rich.Text += (calculateBearing_rapir[i] * 180 / Math.PI).ToString("f4") + "\n"; }
rich.Text += "角度闭合差是" + this.f_angle+"\n";
rich.Text += "近似坐标是" + "\n";
for (int i=0;i<X.Count;i++)
{
rich.Text += "x;" + X[i].ToString("f4") + " "+"y;" + Y[i].ToString("f4") + "\n";
}
rich.Text += "改正坐标是" + "\n";
for (int i = 0; i < X.Count; i++)
{
rich.Text += "x;" + XRapir[i].ToString("f4") + " " + "y;" + YRapir[i].ToString("f4") + "\n";
}
paint(chart);
}
把内容输出在界面的richbox上。
把主界面的计算事件补上
private void 开始计算ToolStripMenuItem_Click(object sender, EventArgs e)
{
Method method = new Method();
method.main(this,this.richTextBox1);
tabControl1.SelectedIndex= 2;
}