C#测绘兰勃特墨卡托投影
先上圖
下載鏈接:程序下載
一、投影變換
正軸等角割圓錐投影:由德國數學家Lambert擬定,屬于蘭勃特正形投影(Lambert projection)之一。
緯線為同心圓弧,經線為放射性直線;相割的兩條緯線是標準緯線,其長度比為1;無角度變形;在兩條割線之內,緯線長度比小于1,之外長度比大于1;離開標緯越遠,變形絕對值越大
正軸等角切圓柱投影,由荷蘭制圖學家Mercator (Mercator Gerardus,1512-1594)于1569年創建,又被稱為墨卡托投影。
經線與緯線是兩組相互垂直的平行直線,經線間距相等,緯線間距由赤道向兩極逐漸增大。
赤道為標準緯線,其余各緯線與赤道等長;無角度變形,但長度和面積變形隨著緯度增高而逐漸增大;等角航線表現為直線
二、變換參數及公式
80坐標系(Xian_1980)
長半軸:6378140 偏心率: 1/298.257
短半軸:6356755.28816
極曲率半徑:6399596.65199
第一偏心率平方: 0.006694384999588
第二偏心率平方: 0.006739501819473
54坐標系(Krasovsky_1940)
長半軸:6378245 偏心率: 1/298.3
短半軸:6356863.01877
極曲率半徑:6399698.90178
第一偏心率平方: 0.006693421622966
第二偏心率平方: 0.006738525414684
蘭勃特正角投影公式
反解公式
墨卡托投影正解
反解公式
三、程序
界面基本的就是 button、 textbox控件
圖可以繪制在 Picturebox 控件,也可以直接畫在form窗體里
可以加入splitContainer控件和groupbox控件
思路
1、讀入數據
CHINA_Arc.gen.txt的數據,將經緯度讀入一個數組,另外定義一個數組專門記錄下標
2、投影變換
將經緯度帶入帶入變換的成員函數進行投影變換
3、畫圖
一共有四百多個環,用for循環依此繪制每個環,如33號環內12個點順序畫線,注意數組的下標錯位現象,不然會導致33號環的最后一個點與34號環的第一個點連線出錯。
老師說經常用For循環會變傻,就這么吧我也想不出更好的方法
源碼
1、輸入參數定義數組
//54坐標系參數double a = 6378245;double b = 6356863.01877;double e1 = Math.Sqrt(0.0066943849995888);double e2 = Math.Sqrt(0.006739501819473);static string path;int[] H = new int[465];static double[] B = new double[26689];static double[] L = new double[26689];double[] BLambert = new double[B.Length];//存儲轉換后的B坐標double[] LLambert = new double[L.Length];//存儲轉換后的L坐標double[] BMercator = new double[B.Length];//存儲轉換后的B坐標double[] LMercator = new double[L.Length];//存儲轉換后的L坐標2、路徑及數據讀入
可以單獨寫一個事件來選擇文件的路徑,OpenFileDialog類提供多種文件的操作,可返回路徑,文件名、文件后綴等
也可以寫死路徑,兩種寫路徑方法,\ 第一個反斜號是轉義字符的意思
path=@"D:\CHINA_Arc.gen.txt"; path="D:\\CHINA_Arc.gen.txt";數據讀入成員函數(注意引用類)
public void inputdata(){StreamReader str = new StreamReader(path);string x;int i = 0;int j = 0;int k = 1;int T;while ((x = str.ReadLine()) != null)//把數據與編號分開存,H[]數組存行號{if (x.Length <= 3 && !x.Contains("END"))T = 1;else if (x.Contains("END"))T = 2;else T = 3;switch (T){case 1:H[i] = k;k++;i++;continue;case 2:k++;continue;case 3:string[] Q = x.Split(',');double u;u = Convert.ToDouble(Q[0]);B[j] = u ;u = Convert.ToDouble(Q[1]);L[j] = u ;j++; k++;continue;}}for (int rr = 0; rr <= 462; rr++){H[rr] = H[rr] - rr;H[462] = 27152;}str.Close();Console.ReadLine();}3、投影成員函數及事件
button事件
private void BtnLambert_Click(object sender, EventArgs e){DateTime t0 = DateTime.Now;Graphics g = this.picBox.CreateGraphics();g.Clear(this.BackColor);g.Dispose();if (TxtB0.Text != "" && TxtL0.Text != "" && TxtB1.Text != "" && TxtB2.Text != ""){ double B0 = Convert.ToDouble(TxtB0.Text) * Math.PI / 180;double L0 = Convert.ToDouble(TxtL0.Text) * Math.PI / 180;double B1 = Convert.ToDouble(TxtB1.Text) * Math.PI / 180;double B2 = Convert.ToDouble(TxtB2.Text) * Math.PI / 180;inputdata();Lambert(B0, B1, B2, e1, L0);drawchina(H, BLambert, LLambert);}elseMessageBox.Show("請輸入數據");DateTime t1 = DateTime.Now;TxtTime.Text = (t1 - t0).ToString();} private void btnMocato_Click(object sender, EventArgs e){DateTime t0 = DateTime.Now;Graphics g = this.picBox.CreateGraphics();g.Clear(this.BackColor);g.Dispose();if (txtB00.Text != "" && txtL00.Text != "" && txtB11.Text != "" ){double B0 = Convert.ToDouble(txtB00.Text) * Math.PI / 180;double L0 = Convert.ToDouble(txtL00.Text) * Math.PI / 180;double B1 = Convert.ToDouble(txtB11.Text) * Math.PI / 180;inputdata();Mercator(B0, B1, e1, e2, L0);drawchina(H, BMercator, LMercator);}elseMessageBox.Show("請輸入數據");DateTime t1 = DateTime.Now;TxtTime.Text = (t1 - t0).ToString();}成員函數
public void Lambert(double B0,double B1,double B2,double e1,double L0){double[] m = new double[B.Length ];double[] t = new double[B.Length];double[] r = new double[B.Length];double[] q = new double[B.Length];double[] c = new double[B.Length];double m0 = Math.Cos(B0) / Math.Sqrt(1 - e1 * e1 * Math.Sin(B0) * Math.Sin(B0));//m0常數double m1 = Math.Cos(B1) / Math.Sqrt(1 - e1 * e1 * Math.Sin(B1) * Math.Sin(B1));//mB1常數double m2 = Math.Cos(B2) / Math.Sqrt(1 - e1 * e1 * Math.Sin(B2) * Math.Sin(B2));//mB2常數double t0 = Math.Tan(Math.PI / 4 - B0 / 2) / Math.Pow((1 - e1 * Math.Sin(B0) / (1 + e1 * Math.Sin(B0))), (e1 / 2));//t0常數double t1 = Math.Tan(Math.PI / 4 - B1 / 2) / Math.Pow((1 - e1 * Math.Sin(B1) / (1 + e1 * Math.Sin(B1))), (e1 / 2));//tB1常數double t2 = Math.Tan(Math.PI / 4 - B2 / 2) / Math.Pow((1 - e1 * Math.Sin(B2) / (1 + e1 * Math.Sin(B2))), (e1 / 2));//tB2常數double n = Math.Log10(m1 / m2) / Math.Log10(t1 / t2);double F = m1 / (n * Math.Pow(t1, n));double r0 = a * F * Math.Pow(t0, n);for (int i = 0; i < B.Length; i++){c[i] = B[i];B[i] = L[i] * Math.PI / 180;L[i] = c[i] * Math.PI / 180;m[i] = Math.Cos(B[i]) / (Math.Sqrt(1 - e1 * e1 * Math.Sin(B[i]) * Math.Sin(B[i])));t[i] = Math.Tan(Math.PI / 4 - B[i] / 2) / Math.Pow((1 - e1 * Math.Sin(B[i]) / (1 + e1 * Math.Sin(B[i]))), (e1 / 2));r[i] = a * F * Math.Pow(t[i], n);q[i] = n * (L[i] - L0);BLambert[i] = (r0 - r[i] * Math.Cos(q[i]));LLambert[i] = (r[i] * Math.Sin(q[i]));}} public void Mercator(double B0, double B1, double e1, double e2, double L0){double K = Math .Pow (a,2) / b / Math.Sqrt(1 + Math.Pow(e2, 2) * Math.Pow(Math.Cos(B0), 2)) * Math.Cos(B0);double[] exchange = new double[B.Length];double[] m = new double[B.Length];double[] n = new double[B.Length];for (int i = 0; i < B.Length; i++){ exchange [i] = B[i];B[i] = L[i] * Math.PI / 180;L[i] = exchange [i] * Math.PI / 180;m[i] = Math.Tan(Math.PI / 4 + B[i] / 2);n[i] = (1 - e1 * Math.Sin(B[i])) / (1 + e1 * Math.Sin(B[i]));BMercator[i] = K*Math.Log(m[i] + Math.Pow(n[i], (e1 / 2)))-2800000;LMercator [i] = K*(L[i]-L0)-50000;}}畫圖成員函數
public void drawchina(int []H,double [] BLambert,double [] LLambert){for (int i = 1; i <= 462; i++)H[i] = H[i] - i - 2;int j = 0; //定義兩個循環體變量,一共462個環,循環462次,每次畫一個環for (int k = 1; k < 462; k++){for (; j < H[k]; j++){if (j == H[k - 1]){j++;}int x1 = (int)(BLambert[j]);int y1 = (int)(LLambert[j]);int x2 = (int)(BLambert[j + 1]);int y2 = (int)(LLambert[j + 1]);drawline(x1, y1, x2, y2);}}}畫線函數
用的是隨機顏色,Random類和 timer控件很好用
投影坐標系和笛卡爾坐標系是反著的(學測繪的都知道的吧)
投影后的坐標都是幾千上萬左右的,需要按比例縮放和平移才能顯示到屏幕上
四、代碼改進
重寫窗口大小
private void ONresize(object sender, EventArgs e)//重寫窗口大小事件{float newx = (this.Width) / x;float newy = (this.Height) / y;setControls(newx, newy, this);}private void setTag(Control cons){foreach (Control con in cons.Controls){con.Tag = con.Width + ";" + con.Height + ";" + con.Left + ";" + con.Top + ";" + con.Font.Size;if (con.Controls.Count > 0){setTag(con);}}}private void setControls(float newx, float newy, Control cons){//遍歷窗體中的控件,重新設置控件的值foreach (Control con in cons.Controls){//獲取控件的Tag屬性值,并分割后存儲字符串數組if (con.Tag != null){string[] mytag = con.Tag.ToString().Split(new char[] { ';' });//根據窗體縮放的比例確定控件的值con.Width = Convert.ToInt32(System.Convert.ToSingle(mytag[0]) * newx);//寬度con.Height = Convert.ToInt32(System.Convert.ToSingle(mytag[1]) * newy);//高度con.Left = Convert.ToInt32(System.Convert.ToSingle(mytag[2]) * newx);//左邊距con.Top = Convert.ToInt32(System.Convert.ToSingle(mytag[3]) * newy);//頂邊距Single currentSize = System.Convert.ToSingle(mytag[4]) * newy;//字體大小con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);if (con.Controls.Count > 0){setControls(newx, newy, con);}}}}總結
以上是生活随笔為你收集整理的C#测绘兰勃特墨卡托投影的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海康、大华设备搜索大概实现原理
- 下一篇: 高效、稳定开发功能的一些心得