一段用C#编写的程序,可以自动生成点和Tin,想学习的可以下载看下

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TIN
{
 /// <summary>
 /// Form1 的摘要说明。
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
  private System.Windows.Forms.PictureBox picTIN;
  private System.Windows.Forms.Button btnDots;
  private System.Windows.Forms.Button btnTIN;
  private System.Windows.Forms.TextBox txtNum;
  private System.Windows.Forms.Label lblNum;
  private Point[] arrDots;
  private ArrayList arrEdges=new ArrayList();
  private ArrayList arrTris=new ArrayList();
  private System.Windows.Forms.Button button1;
  private bool doshow;


  public class Edge
  {
   public int Start;//边的起点
   public int End;//边的终点
   public int LeftTri=-1;//左三角形索引
   public int RightTri=-1;//右三角形索引
  }
  public class Tri
  {
   public int NodeA;
   public int NodeB;
   public int NodeC;
   public int AdjTriA=-1;
   public int AdjTriB=-1;
   public int AdjTriC=-1;
  }
  /// <summary>
  /// 必需的设计器变量。
  /// </summary>
  private System.ComponentModel.Container components = null;

  public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
  }

  /// <summary>
  /// 清理所有正在使用的资源。
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {
   this.picTIN = new System.Windows.Forms.PictureBox();
   this.btnDots = new System.Windows.Forms.Button();
   this.btnTIN = new System.Windows.Forms.Button();
   this.txtNum = new System.Windows.Forms.TextBox();
   this.lblNum = new System.Windows.Forms.Label();
   this.button1 = new System.Windows.Forms.Button();
   this.SuspendLayout();
   //
   // picTIN
   //
   this.picTIN.BackColor = System.Drawing.SystemColors.ControlLightLight;
   this.picTIN.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
   this.picTIN.Location = new System.Drawing.Point(8, 8);
   this.picTIN.Name = "picTIN";
   this.picTIN.Size = new System.Drawing.Size(500, 500);
   this.picTIN.TabIndex = 0;
   this.picTIN.TabStop = false;
   //
   // btnDots
   //
   this.btnDots.Location = new System.Drawing.Point(520, 80);
   this.btnDots.Name = "btnDots";
   this.btnDots.Size = new System.Drawing.Size(88, 32);
   this.btnDots.TabIndex = 1;
   this.btnDots.Text = "生成随机点";
   this.btnDots.Click += new System.EventHandler(this.btnDots_Click);
   //
   // btnTIN
   //
   this.btnTIN.Enabled = false;
   this.btnTIN.Location = new System.Drawing.Point(520, 136);
   this.btnTIN.Name = "btnTIN";
   this.btnTIN.Size = new System.Drawing.Size(88, 32);
   this.btnTIN.TabIndex = 2;
   this.btnTIN.Text = "生成TIN";
   this.btnTIN.Click += new System.EventHandler(this.btnTIN_Click);
   //
   // txtNum
   //
   this.txtNum.Location = new System.Drawing.Point(520, 48);
   this.txtNum.Name = "txtNum";
   this.txtNum.Size = new System.Drawing.Size(80, 21);
   this.txtNum.TabIndex = 3;
   this.txtNum.Text = "10";
   this.txtNum.TextChanged += new System.EventHandler(this.txtNum_TextChanged);
   //
   // lblNum
   //
   this.lblNum.Location = new System.Drawing.Point(520, 32);
   this.lblNum.Name = "lblNum";
   this.lblNum.Size = new System.Drawing.Size(80, 16);
   this.lblNum.TabIndex = 4;
   this.lblNum.Text = "随机点数目:";
   //
   // button1
   //
   this.button1.Enabled = false;
   this.button1.Location = new System.Drawing.Point(520, 200);
   this.button1.Name = "button1";
   this.button1.Size = new System.Drawing.Size(88, 32);
   this.button1.TabIndex = 5;
   this.button1.Text = "演示生成过程";
   this.button1.Click += new System.EventHandler(this.button1_Click);
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.ClientSize = new System.Drawing.Size(624, 518);
   this.Controls.Add(this.button1);
   this.Controls.Add(this.lblNum);
   this.Controls.Add(this.txtNum);
   this.Controls.Add(this.btnTIN);
   this.Controls.Add(this.btnDots);
   this.Controls.Add(this.picTIN);
   this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
   this.MaximizeBox = false;
   this.Name = "Form1";
   this.Text = "TIN自动生成演示程序";
   this.ResumeLayout(false);

  }
  #endregion

  /// <summary>
  /// 应用程序的主入口点。
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  private void btnDots_Click(object sender, System.EventArgs e)
  {
   //生成指定数目的随机点,并显示在picTIN里
   GeneDots();  
  }
  private void GeneDots()
  {
   int num=Convert.ToInt32(txtNum.Text);
   if(num<3)
    MessageBox.Show("点数太少,请输入一个大于3的值");
   else if(num>1000)
    MessageBox.Show("本程序只用于演示,请勿输入大数以免浪费时间。建议输入1000以内的数");
   else
   {
    arrDots=new Point[num];
    Random rdm=new Random();
    for(int i=0;i<num;i++)
    {
     arrDots[i].X=rdm.Next(0,500);
     arrDots[i].Y=rdm.Next(0,500);
    }
    this.picTIN.Paint-=new PaintEventHandler(picTIN_DrawTIN);
    this.picTIN.Paint+=new PaintEventHandler(picTIN_DrawDots);
    this.picTIN.Refresh();
    this.btnTIN.Enabled=true;
    this.button1.Enabled=true;
   }
  }
  private void btnTIN_Click(object sender, System.EventArgs e)
  {
   //this.btnTIN.Enabled=false;
   //生成并绘制TIN
   doshow=false;
   GeneTIN();
  }

  private void picTIN_DrawDots(object sender, PaintEventArgs e)
  {
   int num=arrDots.Length;
   for(int i=0;i<num;i++)
   {
    e.Graphics.DrawRectangle(Pens.Red,arrDots[i].X,arrDots[i].Y,1,1);
   }
  }

  private void txtNum_TextChanged(object sender, System.EventArgs e)
  {
   string txt=txtNum.Text;
   int i=txt.Length;
   if( i < 1)
    return;
   for(int m = 0; m < i; m ++)
   {
    string str = txt.Substring(m, 1);
    if( !Char.IsNumber( Convert.ToChar(str) ))
    {
                    txtNum.Text = txtNum.Text.Replace(str, ""); //将非数字文本过滤掉
                    txtNum.SelectionStart = txtNum.Text.Length;//将光标定位到最后一位
                }
            }
  }

  private void picTIN_DrawTIN(object sender, PaintEventArgs e)
  {
   for(int i=0;i<arrEdges.Count;i++)
   {
    Edge eg=(Edge)arrEdges[i];
    Point pt1,pt2;
    pt1=arrDots[eg.Start];
    pt2=arrDots[eg.End];
    e.Graphics.DrawLine(Pens.Black,pt1,pt2);
   }
  }
  private void GeneTIN()
  {
   arrEdges.Clear();
   arrTris.Clear();
   int i,idxStart=0,endTemp,ptindex;
   bool isExist;
   double angMax,angMin,angTemp,angRcdMax,angRcdTmp,lenMin,lenCur,lenTmp1,lenTmp2;
   Edge edge=new Edge();
   this.picTIN.Paint-=new PaintEventHandler(picTIN_DrawTIN);
   this.picTIN.Paint+=new PaintEventHandler(picTIN_DrawTIN);


   //找到边界---(删除不需要的点,从X最小的地方开始找,直至回到起始点)
   Point dirCur=new Point();
   Point dirTmp1=new Point();
   Point dirTmp2=new Point();
   Point ptStart=new Point();

   for(i=1;i<arrDots.Length;i++)
   {
    if(arrDots[i].X<arrDots[idxStart].X)
    {
     idxStart=i;
    }
   }
   endTemp=idxStart-1;
   ptStart.X=arrDots[idxStart].X;
   ptStart.Y=arrDots[idxStart].Y;
   edge.Start=idxStart;
   angMin=Math.PI;
   dirCur.X=0;
   dirCur.Y=500;
   while(endTemp!=idxStart)
   {
    lenCur=Math.Sqrt(dirCur.X*dirCur.X+dirCur.Y*dirCur.Y);
    lenMin=1000;
    for(i=0;i<arrDots.Length;i++)//找边界
    {
    
     if(i!=edge.Start)
     {
      dirTmp1.X=arrDots[i].X-ptStart.X;
      dirTmp1.Y=arrDots[i].Y-ptStart.Y;
      lenTmp1=Math.Sqrt(dirTmp1.X*dirTmp1.X+dirTmp1.Y*dirTmp1.Y);
      angTemp=Math.Acos((dirCur.X*dirTmp1.X+dirCur.Y*dirTmp1.Y)/(lenTmp1*lenCur));
      if(angTemp<angMin)
      {
       angMin=angTemp;
       edge.End=i;
       lenMin=lenTmp1;
      }
      else if(angTemp==angMin && lenTmp1<lenMin)
      {
       edge.End=i;
       lenMin=lenTmp1;
      }
     }
    }
    arrEdges.Add(edge);
    if(doshow==true)
    {
     System.Threading.Thread.Sleep(500);
     this.picTIN.Refresh();
    }
    endTemp=edge.End;
    edge=new Edge();
    angMin=Math.PI;
    dirCur.X=arrDots[endTemp].X-ptStart.X;
    dirCur.Y=arrDots[endTemp].Y-ptStart.Y;
    ptStart=arrDots[endTemp];
    edge.Start=endTemp;
   }
   if(doshow==true)
   {
    System.Threading.Thread.Sleep(500);
    this.picTIN.Refresh();
   }
   //以下为自动生成TIN
   //从第一条边开始,按照先左后右的顺序寻找,找到则加入三角形数组和边数组,没有则继续下一边,直到边到达最后
   //注意边可能有两种顺序存储。
   for(i=0;i<arrEdges.Count;i++)
   {
    //取出一条边
    edge=new Edge();
    edge=(Edge)arrEdges[i];
    //先左后右计算扩展点-判断三角形是否存在过(若本边的左三角已存在,则计算右三角)??
    if(edge.LeftTri==-1)
    {
     ptindex=-1;//选中的点的index
     dirCur.X=arrDots[edge.End].X-arrDots[edge.Start].X;
     dirCur.Y=arrDots[edge.End].Y-arrDots[edge.Start].Y;
     angRcdMax=0;//与该边夹角最大值
     angMax=0;//最大圆内接角
     for(int j=0;j<arrDots.Length;j++)
     {
      if(j!=edge.Start && j!=edge.End)//排除边的端点
      {
       dirTmp1.X=arrDots[j].X-arrDots[edge.Start].X;
       dirTmp1.Y=arrDots[j].Y-arrDots[edge.Start].Y;
       if(dirCur.X*dirTmp1.Y-dirCur.Y*dirTmp1.X<0)//如果该点在左边,则计算
       {
        //找角度最大的
        lenCur=Math.Sqrt(dirCur.X*dirCur.X+dirCur.Y*dirCur.Y);//当前向量长度
        lenTmp1=Math.Sqrt(dirTmp1.X*dirTmp1.X+dirTmp1.Y*dirTmp1.Y);

        dirTmp2.X=arrDots[j].X-arrDots[edge.End].X;
        dirTmp2.Y=arrDots[j].Y-arrDots[edge.End].Y;
        lenTmp2=Math.Sqrt(dirTmp2.X*dirTmp2.X+dirTmp2.Y*dirTmp2.Y);
        angRcdTmp=Math.Acos((dirCur.X*dirTmp1.X+dirCur.Y*dirTmp1.Y)/(lenTmp1*lenCur));
        angTemp=Math.Acos((dirTmp2.X*dirTmp1.X+dirTmp2.Y*dirTmp1.Y)/(lenTmp1*lenTmp2));
        if(angTemp>angMax)
        {
         angMax=angTemp;
         angRcdMax=angRcdTmp;
         ptindex=j;
        }
        else if(angTemp==angMax && angRcdMax<angRcdTmp)//相等取最左
        {
         angRcdMax=angRcdTmp;
         ptindex=j;
        }

       }
      }
     }
     if(ptindex!=-1)//选择有点
     {
      //记录三角形
      Tri tri=new Tri();
      tri.NodeA=edge.Start;
      tri.NodeB=edge.End;
      tri.NodeC=ptindex;
      edge.LeftTri=arrTris.Count;


      isExist=false;
      //记录边1-需要检索是否存在过这条边-由于每条边都先有左三角形,如有三角形加入,必定为右三角形
      for(int k=0;k<arrEdges.Count;k++)
      {
       Edge e=(Edge)arrEdges[k];
       if(e.Start==edge.Start && e.End==ptindex)//如果存在过这条边,则记录其右三角形
       {
        e.RightTri=arrTris.Count;
        tri.AdjTriB=e.LeftTri;
        isExist=true;
        break;
       }
       else if(e.Start==ptindex && e.End==edge.Start)
       {
        e.LeftTri=arrTris.Count;
        tri.AdjTriB=e.RightTri;
        isExist=true;
        break;
       }
      }
      if(isExist==false)//如果不存在这条边,则新建一条边
      {
       Edge edgeadd=new Edge();
       edgeadd.Start=ptindex;
       edgeadd.End=edge.Start;
       edgeadd.LeftTri=arrTris.Count;
       arrEdges.Add(edgeadd);
       if(doshow==true)
       {
        System.Threading.Thread.Sleep(500);
        this.picTIN.Refresh();
       }

      }


      isExist=false;
      //记录边2
      for(int k=0;k<arrEdges.Count;k++)
      {
       Edge e=(Edge)arrEdges[k];
       if(e.Start==ptindex && e.End==edge.End)//如果存在过这条边,则记录其右三角形
       {
        e.RightTri=arrTris.Count;
        tri.AdjTriA=e.LeftTri;
        isExist=true;
        break;
       }
       else if(e.Start==edge.End && e.End==ptindex)
       {
        e.LeftTri=arrTris.Count;
        tri.AdjTriA=e.RightTri;
        isExist=true;
        break;
       }
      }
      if(isExist==false)//如果不存在这条边,则新建一条边
      {
       Edge edgeadd=new Edge();
       edgeadd.Start=edge.End;
       edgeadd.End=ptindex;
       edgeadd.LeftTri=arrTris.Count;
       arrEdges.Add(edgeadd);
       if(doshow==true)
       {
        System.Threading.Thread.Sleep(500);
        this.picTIN.Refresh();
       }

      }
      tri.AdjTriC=edge.RightTri;//如果edge的右三角形不存在,由if进来可见左三角也不存在,这只能是边界,从而tri.AdjTriC=-1合理
      arrTris.Add(tri);//add the tri to the arraylist
     }
    }
    else if(edge.RightTri==-1)//由于最开始的那部分都是边界,只有一个三角形;以后的边都已存在一个三角形,也仅剩余一个,故可以else if
    {
     //仅在右边找
     ptindex=-1;//选中的点的index
     dirCur.X=arrDots[edge.End].X-arrDots[edge.Start].X;
     dirCur.Y=arrDots[edge.End].Y-arrDots[edge.Start].Y;
     angMax=0;//最大角度
     angRcdMax=0;//与该边夹角最大值
     for(int j=0;j<arrDots.Length;j++)
     {
      if(j!=edge.Start && j!=edge.End)//排除边的端点
      {
       lenCur=Math.Sqrt(dirCur.X*dirCur.X+dirCur.Y*dirCur.Y);//当前向量长度
       dirTmp1.X=arrDots[j].X-arrDots[edge.Start].X;
       dirTmp1.Y=arrDots[j].Y-arrDots[edge.Start].Y;
       if(dirCur.X*dirTmp1.Y-dirCur.Y*dirTmp1.X>0)//如果该点在右边,则计算
       {
        //找角度最大的
        lenTmp1=Math.Sqrt(dirTmp1.X*dirTmp1.X+dirTmp1.Y*dirTmp1.Y);

        dirTmp2.X=arrDots[j].X-arrDots[edge.End].X;
        dirTmp2.Y=arrDots[j].Y-arrDots[edge.End].Y;
        lenTmp2=Math.Sqrt(dirTmp2.X*dirTmp2.X+dirTmp2.Y*dirTmp2.Y);
        angRcdTmp=Math.Acos((dirCur.X*dirTmp1.X+dirCur.Y*dirTmp1.Y)/(lenTmp1*lenCur));
        angTemp=Math.Acos((dirTmp2.X*dirTmp1.X+dirTmp2.Y*dirTmp1.Y)/(lenTmp1*lenTmp2));
        if(angTemp>angMax)
        {
         angMax=angTemp;
         angRcdMax=angRcdTmp;
         ptindex=j;
        }
        else if(angTemp==angMax && angRcdTmp>angRcdTmp)//相等取最左
        {
         angRcdTmp=angRcdTmp;
         ptindex=j;
        }

       }
      }
     }
     if(ptindex!=-1)//选择有点
     {
      //记录三角形
      //记录三角形
      Tri tri=new Tri();
      tri.NodeA=edge.Start;
      tri.NodeB=edge.End;
      tri.NodeC=ptindex;
      edge.RightTri=arrTris.Count;


      isExist=false;
      //记录边1-需要检索是否存在过这条边-由于每条边都先有左三角形,如有三角形加入,必定为右三角形
      for(int k=0;k<arrEdges.Count;k++)
      {
       Edge e=(Edge)arrEdges[k];
       if(e.Start==ptindex && e.End==edge.Start)//如果存在过这条边,则记录其右三角形
       {
        e.RightTri=arrTris.Count;
        tri.AdjTriB=e.LeftTri;
        isExist=true;
        break;
       }
       else if(e.Start==edge.Start && e.End==ptindex)
       {
        e.LeftTri=arrTris.Count;
        tri.AdjTriB=e.RightTri;
        isExist=true;
        break;

       }
      }
      if(isExist==false)//如果不存在这条边,则新建一条边
      {
       Edge edgeadd=new Edge();
       edgeadd.Start=edge.Start;
       edgeadd.End=ptindex;
       edgeadd.LeftTri=arrTris.Count;
       arrEdges.Add(edgeadd);
       if(doshow==true)
       {
        System.Threading.Thread.Sleep(500);
        this.picTIN.Refresh();
       }

      }
      isExist=false;
      //记录边2
      for(int k=0;k<arrEdges.Count;k++)
      {
       Edge e=(Edge)arrEdges[k];
       if(e.Start==edge.End && e.End==ptindex)//如果存在过这条边,则记录其右三角形
       {
        e.RightTri=arrTris.Count;
        tri.AdjTriA=e.LeftTri;
        isExist=true;
        break;
       }
       else if(e.Start==ptindex && e.End==edge.End)
       {
        e.LeftTri=arrTris.Count;
        tri.AdjTriA=e.RightTri;
        isExist=true;
        break;
       }
      }
      if(isExist==false)//如果不存在这条边,则新建一条边
      {
       Edge edgeadd=new Edge();
       edgeadd.Start=ptindex;
       edgeadd.End=edge.End;
       edgeadd.LeftTri=arrTris.Count;
       arrEdges.Add(edgeadd);
       if(doshow==true)
       {
        System.Threading.Thread.Sleep(500);
        this.picTIN.Refresh();
       }
      }
      tri.AdjTriC=edge.LeftTri;//如果edge的左三角形不存在,由if进来可见右三角也不存在,这只能是边界,从而tri.AdjTriC=-1合理
      arrTris.Add(tri);//add the tri to the arraylist 
     }

    }
    
   }

 


   this.picTIN.Refresh();
  }

  private void button1_Click(object sender, System.EventArgs e)
  {
   doshow=true;
   GeneTIN();

  
  }
 }
}
来自:http://bbs.esrichina-bj.cn/ESRI/viewthread.php?tid=36377&extra=page%3D6%26amp%3Bfilter%3Dtype%26amp%3Btypeid%3D6

posted @ 2009-03-12 15:01  闫磊博客  阅读(601)  评论(0)    收藏  举报