三角網生長算法構建TIN

三角網生長算法構建TIN

本文內容實現均用C#

1、構建三角形和點存儲結構

public string Filename;
        public System.Drawing.Bitmap curBitmap;
        public Form1()
        {
            InitializeComponent();
        }
        int[] t1 = new int[1000];
        int[] t2 = new int[1000];
        int[] t3 = new int[1000];
        //創建高程點的結構,存儲高程點的名稱,X、Y座標,高程H值
        public struct Point
        {
            public int Number;
            public string Name;      //存儲點的名稱
            public double x;         //存儲點的X座標
            public double y;         //存儲點的Y座標
            public double h;         //存儲點的高程值H
        }
        Point[] pt = new Point[1000];   //定義初始的點數組大小爲1000
        int Lines;                      //記錄文件的行數,即點的個數
        double xmax, xmin, ymax, ymin;  //記錄所有點中的x,y座標最大最小值
        int K;

2、打開高程點數據文件

//打開高程點數據文件
        private void 打開OToolStripMenuItem_Click(object sender, EventArgs e)
        {

            OpenFileDialog filename = new OpenFileDialog();
            filename.Filter = "All files(*.*)|*.*|txt files(*.txt)|*.txt|dat files(*.dat)|*.dat";
            filename.FilterIndex = 2;
            //filename.RestoreDirectory = true;                          
            if (filename.ShowDialog() == DialogResult.OK)
            {
                Filename = filename.FileName.ToString();
                string[] lines = File.ReadAllLines(Filename);
                Lines = lines.Length;
                for (int i = 1; i <= Lines; i++)
                {
                    string[] sArray = lines[i - 1].Split(',');  //按","將每一行分割成四個字符串
                    pt[i].Number = i;
                    pt[i].Name = sArray[0];
                    pt[i].x = Convert.ToDouble(sArray[1]);
                    pt[i].y = Convert.ToDouble(sArray[2]);
                    pt[i].h = Convert.ToDouble(sArray[3]);
                }
            }
        }

3、確定所有點的範圍

//確定所有點的範圍
        private void Area()
        {
            xmax = xmin = pt[1].x;
            ymax = ymin = pt[1].y;
            for (int i = 2; i <= Lines; i++)
            {
                if (xmax < pt[i].x) xmax = pt[i].x;
                if (xmin > pt[i].x) xmin = pt[i].x;
                if (ymax < pt[i].y) ymax = pt[i].y;
                if (ymin > pt[i].y) ymin = pt[i].y;
            }
        }

4、計算座標轉換比例因子

 //計算座標轉換比例因子
        public double CalcScale()
        {
            Area();
            Rectangle m_rect = pictureBox1.ClientRectangle;
            double ds = 1.0;
            double dsx, dsy;
            if ((xmax - xmin != 0) && (ymax - ymin != 0))
            {
                dsx = Math.Abs((xmax - xmin) / m_rect.Height);
                dsy = Math.Abs((ymax - ymin) / m_rect.Width);
                ds = Math.Max(dsx, dsy);
            }
            else
            {
                if (xmax - xmin != 0)
                {
                    ds = Math.Abs((xmax - xmin) / m_rect.Height);
                }
                else
                {
                    if (ymax - ymin != 0)
                    {
                        ds = Math.Abs((ymax - ymin) / m_rect.Width);
                    }
                    else { ds = 1; }
                }
            }
            return ds;
        }

5、找到最近的兩個高程點

 //找到兩個最近的高程點
        public void MinDistance(Point[] pt, out int pt1, out int pt2)
        {
            int i, j;
            double[,] Distance = new double[Lines, Lines];
            //將任意兩點間的距離存儲到矩陣Distance中
            for (i = 1; i <= Lines; i++)
                for (j = i + 1; j < Lines; j++)
                    if (i != j)
                        Distance[i, j] = Math.Sqrt(Math.Pow(pt[i].x - pt[j].x, 2) + Math.Pow(pt[i].y - pt[j].y, 2));
            double[] Mindistance = { 10000, 0, 0 };
            //找到矩陣Distance中的最小值,並記錄行列號
            for (i = 1; i <= Lines; i++)
                for (j = i + 1; j < Lines; j++)
                    if (Mindistance[0] > Distance[i, j])
                    {
                        Mindistance[0] = Distance[i, j];
                        Mindistance[1] = i;
                        Mindistance[2] = j;
                    }
            pt1 = (int)Mindistance[1];
            pt2 = (int)Mindistance[2];
        }

6、找到離中點最近的點

//找到離中點最近的點
        public void Find(int pt1, int pt2, out int pt3)
        {
            int i;
            double meanx = (pt[pt1].x + pt[pt2].x) / 2;
            double meany = (pt[pt1].y + pt[pt2].y) / 2;
            double Min = 10000000000;
            pt3 = 0;
            for (i = 1; i <= Lines; i++)
            {
                if (i != pt1 && i != pt2)
                {
                    double temp = Math.Sqrt(Math.Pow(pt[i].x - meanx, 2) + Math.Pow(pt[i].y - meany, 2));
                    if (Min > temp)
                    {
                        Min = temp;
                        pt3 = i;
                    }
                }
            }
        }

7、判斷三角形擴展是否在同一側

//判斷三角形擴展點是否在同一側
        public bool Direction(int point1, int point2, int point3, int point4)
        {
            //計算直線方程的係數a,b
            double a = (pt[point2].y - pt[point1].y) / (pt[point2].x - pt[point1].x);
            double b = (pt[point1].x * pt[point2].y - pt[point2].x * pt[point1].y) / (pt[point2].x - pt[point1].x);
            double fxy1 = pt[point3].y - (a * pt[point3].x - b);
            double fxy2 = pt[point4].y - (a * pt[point4].x - b);
            //當位於非同一側時
            if (fxy1 < 0 && fxy2 > 0 || fxy1 > 0 && fxy2 < 0)
                return true;
            //當位於同一側時
            else return false;
        }

8、計算擴展邊的角度餘弦值

//計算擴展邊的角度餘弦值
        public double Angle(int pt1, int pt2, int pt3)
        {
            double angle;
            double L1 = Math.Sqrt((pt[pt2].x - pt[pt3].x) * (pt[pt2].x - pt[pt3].x) + (pt[pt2].y - pt[pt3].y) * (pt[pt2].y - pt[pt3].y));
            double L2 = Math.Sqrt((pt[pt1].x - pt[pt3].x) * (pt[pt1].x - pt[pt3].x) + (pt[pt1].y - pt[pt3].y) * (pt[pt1].y - pt[pt3].y));
            double L3 = Math.Sqrt((pt[pt2].x - pt[pt1].x) * (pt[pt2].x - pt[pt1].x) + (pt[pt2].y - pt[pt1].y) * (pt[pt2].y - pt[pt1].y));
            angle = (L1 * L1 + L2 * L2 - L3 * L3) / (2 * L1 * L2);
            return angle;
        }

9、找到擴展邊形成張角最大的點

//找到擴展邊形成張角最大的點
        private int MaxAngle(int[] x, int A, int B, int n)
        {
            double C = 0, temp, s = 0;
            int max = 0;
            for (int i = 1; i <= n; i++)
            {
                if (x[i] != A && x[i] != B)
                {
                    s = Angle(A, B, x[i]);
                    if (s < 1)
                        C = Math.Acos(s);
                    else C = 0;
                    max = x[i];
                    break;
                }
            }
            for (int i = 1; i <= n; i++)
            {
                if (i != A && i != B)
                {
                    s = Angle(A, B, x[i]);
                    if (s < 1)
                        temp = Math.Acos(s);
                    else temp = 0;
                    if (temp > C)
                    {
                        C = temp;
                        max = x[i];
                    }
                }
            }
            return max;
        }

10、判斷三角形的一條邊是否已經出現過兩次

 //判斷三角形的一條邊是否已經出現過兩次
        public bool Repeat(int point1, int point2, int L)
        {
            int sum = 0;
            for (int i = 1; i <= L; i++)
            {
                if (point1 == t1[i] && point2 == t2[i] || point1 == t2[i] && point2 == t1[i] ||
                    point1 == t2[i] && point2 == t3[i] || point1 == t3[i] && point2 == t2[i] ||
                    point1 == t3[i] && point2 == t1[i] || point1 == t1[i] && point2 == t3[i])
                {
                    sum++;
                    if (sum == 2)
                        return false;
                }
            }
            return true;
        }

12、構建並繪製TIN

private void 構建TINCToolStripMenuItem_Click(object sender, EventArgs e)
        {

            //找到所有點中距離最小的兩個點,作爲第一個三角形的第一個點和第二個點
            MinDistance(pt, out int point1, out int point2);
            t1[1] = point1;
            t2[1] = point2;

            //尋找第一個三角形的第三個點:離第一條邊距離最短的點
            Find(point1, point2, out int point3);
            t3[1] = point3;

            //設置計數變量K記錄擴展的三角形數
            K = 0;
            //設置計數變量L記錄已經形成的三角形數
            int L = 1;
            //設置數組存儲可能的擴展點
            int[] x = new int[Lines];

            //擴展三角形
            while (K != L)
            {
                K++;
                point1 = t1[K];
                point2 = t2[K];
                point3 = t3[K];

                //第一條擴展邊不重複,沒有被兩個三角形共用
                if (Repeat(point1, point2, L))
                {
                    //判斷新擴展的邊
                    int t = 0;
                    x[t++] = 0;
                    //尋找可能的擴展點
                    for (int i = 1; i <= Lines; i++)
                        if (i != point1 && i != point2 && i != point3 && Direction(point1, point2,point3, i))
                        {
                            x[t++] = i;
                        }
                    //存在擴展點
                    if (t > 1)
                    {
                        int max = MaxAngle(x, point1, point2, t - 1);
                        L = L + 1;
                        t1[L] = point1;
                        t2[L] = point2;
                        t3[L] = max;
                    }
                }

                //第二條擴展邊不重複,沒有被兩個三角形共用
                if (Repeat(point1, point3, L))
                {
                    int t = 0;
                    x[t++] = 0;
                    for (int i = 1; i <= Lines; i++)
                        if (i != point1 && i != point3 && i != point2 && Direction(point1, point3, point2, i))
                        {
                            x[t++] = i;
                        }
                    if (t > 1)
                    {
                        int max = MaxAngle(x, point1, point3, t - 1);
                        L = L + 1;
                        t1[L] = point1;
                        t2[L] = point3;
                        t3[L] = max;
                    }
                }

                //第三條擴展邊不重複,沒有被兩個三角形共用
                if (Repeat(point2, point3, L))
                {
                    int t = 0;
                    x[t++] = 0;
                    for (int i = 1; i <= Lines; i++)
                        if (i != point2 && i != point3 && i != point1 && Direction(point2, point3, point1, i))
                        {
                            x[t++] = i;
                        }
                    if (t > 1)
                    {
                        int max = MaxAngle(x, point2, point3, t - 1);
                        L = L + 1;
                        t1[L] = point2;
                        t2[L] = point3;
                        t3[L] = max;
                    }
                }
            }

            //繪製TIN
            Graphics g = pictureBox1.CreateGraphics();
            double m_scale = CalcScale();
            Pen mypen = new Pen(Color.Red, 1);                   //創建畫筆
            Rectangle m_rect = pictureBox1.ClientRectangle;      //獲得畫布大小
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //消除鋸齒
            for (int i = 1; i <= L; i++)
            {
                //由測量座標計算屏幕座標
                double ix1 = (pt[t1[i]].y - ymin) / m_scale;
                double iy1 = m_rect.Height - (pt[t1[i]].x - xmin) / m_scale - 20;

                double ix2 = (pt[t2[i]].y - ymin ) / m_scale;
                double iy2 = m_rect.Height - (pt[t2[i]].x - xmin) / m_scale - 20;

                double ix3 = (pt[t3[i]].y - ymin) / m_scale;
                double iy3 = m_rect.Height - (pt[t3[i]].x - xmin) / m_scale - 20;


                g.DrawLine(mypen, (float)ix1, (float)iy1, (float)ix2, (float)iy2);
                g.DrawLine(mypen, (float)ix1, (float)iy1, (float)ix3, (float)iy3);
                g.DrawLine(mypen, (float)ix3, (float)iy3, (float)ix2, (float)iy2);
            }
            //g.Dispose();
        }

展點結果

在這裏插入圖片描述

設計界面

功能菜單設置-1
在這裏插入圖片描述
在這裏插入圖片描述

繪製TIN結果

在這裏插入圖片描述

高程點文件內容:()

1,512851.699,1121834.867,210.310
2,512850.236,1121835.836,210.430
3,512848.802,1121836.824,210.310
4,512847.151,1121814.595,210.290
5,512849.057,1121831.194,210.440
6,512846.319,1121834.680,210.360
7,512847.872,1121828.652,210.430
8,512844.406,1121835.692,210.410
9,512849.974,1121822.530,210.350
10,512847.420,1121826.715,210.330
11,512841.893,1121816.777,210.380
12,512842.204,1121833.716,210.390
13,512845.495,1121825.847,210.410
14,512847.488,1121821.435,210.470
15,512839.877,1121837.289,210.520
16,512842.601,1121829.914,210.470
17,512847.693,1121830.249,210.360
18,512843.665,1121825.828,210.440
19,512841.285,1121830.542,210.350
20,512850.042,1121810.872,210.320
21,512850.820,1121807.228,210.350
22,512839.262,1121831.614,210.430
23,512840.900,1121826.505,210.360
24,512847.948,1121806.836,210.330
25,512839.078,1121822.817,210.360
26,512851.561,1121787.907,210.460
27,512836.039,1121822.946,210.330
28,512843.538,1121805.103,210.410
29,512845.537,1121792.055,211.540
30,512848.374,1121791.586,211.930
31,512849.211,1121789.581,211.860
32,512831.485,1121831.862,210.350
33,512841.485,1121810.862,210.350
34,512835.537,1121810.055,211.540
35,512838.540,1121805.496,210.528
36,512830.158,1121800.693,211.359
37,512840.088,1121790.363,210.358
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章