C#测绘兰勃特墨卡托投影

先上图

C#测绘兰勃特墨卡托投影_第1张图片

下载链接:程序下载

一、投影变换

正轴等角割圆锥投影:由德国数学家Lambert拟定,属于兰勃特正形投影(Lambert projection)之一。

C#测绘兰勃特墨卡托投影_第2张图片
纬线为同心圆弧,经线为放射性直线;相割的两条纬线是标准纬线,其长度比为1;无角度变形;在两条割线之内,纬线长度比小于1,之外长度比大于1;离开标纬越远,变形绝对值越大
C#测绘兰勃特墨卡托投影_第3张图片

正轴等角切圆柱投影,由荷兰制图学家Mercator (Mercator Gerardus,1512-1594)于1569年创建,又被称为墨卡托投影。

C#测绘兰勃特墨卡托投影_第4张图片
经线与纬线是两组相互垂直的平行直线,经线间距相等,纬线间距由赤道向两极逐渐增大。
赤道为标准纬线,其余各纬线与赤道等长;无角度变形,但长度和面积变形随着纬度增高而逐渐增大;等角航线表现为直线

C#测绘兰勃特墨卡托投影_第5张图片

二、变换参数及公式

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

兰勃特正角投影公式

C#测绘兰勃特墨卡托投影_第6张图片
反解公式
C#测绘兰勃特墨卡托投影_第7张图片

墨卡托投影正解
C#测绘兰勃特墨卡托投影_第8张图片
反解公式
C#测绘兰勃特墨卡托投影_第9张图片

三、程序

界面基本的就是 button、 textbox控件
图可以绘制在 Picturebox 控件,也可以直接画在form窗体里
可以加入splitContainer控件和groupbox控件

思路
1、读入数据

C#测绘兰勃特墨卡托投影_第10张图片
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类提供多种文件的操作,可返回路径,文件名、文件后缀等

            OpenFileDialog fdlg = new OpenFileDialog();
            fdlg.Title = "C# Corner Open FileDialog";
            fdlg.InitialDirectory = "";
            fdlg.Filter = "All files (*.*)|*.*|All files(*.*)|*.*";
            fdlg.FilterIndex = 2;
            fdlg.RestoreDirectory = true;
            if(fdlg .ShowDialog ()==DialogResult.OK )
            {
     
                path = Path.GetFullPath(fdlg.FileName);//获取绝对路径
            }
            MessageBox.Show("文件选择完成!");

也可以写死路径,两种写路径方法,\ 第一个反斜号是转义字符的意思

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);
            }
            else
                MessageBox.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);
            }
            else
                MessageBox.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控件很好用
投影坐标系和笛卡尔坐标系是反着的(学测绘的都知道的吧)
投影后的坐标都是几千上万左右的,需要按比例缩放和平移才能显示到屏幕上

public void drawline(int x1, int y1, int x2, int y2)
        {
     
            Random rnd = new Random();
            Graphics g = this.picBox.CreateGraphics();
            Pen map = new Pen(Color.FromArgb (rnd.Next (256), rnd.Next (50), rnd.Next (50)), 2f);//定义画刷,黑色,线条宽度为1,f表示float浮点数
            g.ScaleTransform(0.00009f, 0.00009f);//画面缩小
            g.TranslateTransform(4000000, 6400000);//平移
            g.RotateTransform(-90);//旋转      
            g.DrawLine(map, x1, y1, x2, y2);//每次两个点连线  
        }

四、代码改进

重写窗口大小

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#程序,地图学投影,文件读取)