//自定义函数,计算节点到线段的距离
        private double Distanct(Pnt P0, Pnt P1, Pnt tempPnt)
        {
            double L0, L1, L2;

            L0 = Math.Sqrt((P0.x - P1.x) * (P0.x - P1.x) + (P0.y - P1.y) * (P0.y - P1.y));
            L1 = Math.Sqrt((tempPnt.x - P1.x) * (tempPnt.x - P1.x) + (tempPnt.y - P1.y) * (tempPnt.y - P1.y));
            L2 = Math.Sqrt((P0.x - tempPnt.x) * (P0.x - tempPnt.x) + (P0.y - tempPnt.y) * (P0.y - tempPnt.y));
            double P;

            P = (L0 + L1 + L2) / 2;
            double S;

            S = Math.Sqrt(P * (P - L0) * (P - L1) * (P - L2));
            double D;

            D = 2 * S / L0;
            return(D);
        }
        private void toolJS_Click(object sender, EventArgs e)
        {
            //从表格中读取节点数据到原始节点的数组中
            int intoriPntNum = dataGridView1.Rows.Count - 1;

            Pnt[] oriPnt = new Pnt[intoriPntNum];
            for (int i = 0; i <= intoriPntNum - 1; i++)
            {
                oriPnt[i]    = new Pnt();
                oriPnt[i].ID = Convert.ToInt16(dataGridView1.Rows[i].Cells[0].Value);
                oriPnt[i].x  = Convert.ToDouble(dataGridView1.Rows[i].Cells[1].Value);
                oriPnt[i].y  = Convert.ToDouble(dataGridView1.Rows[i].Cells[2].Value);
            }
            //DP算法
            //声明变量和堆栈
            Pnt         P0       = new Pnt();                                //声明线段起点
            Pnt         P1       = new Pnt();                                //声明线段终点
            Stack <Pnt> proPnt   = new Stack <Pnt>();                        //待检查的节点堆栈
            Stack <Pnt> rePnt    = new Stack <Pnt>();                        //压缩结果的堆栈
            int         intYuZhi = Convert.ToInt16(toolStripComboBox1.Text); //读取阈值

            P0 = oriPnt[0];                                                  //设置初始起点
            P1 = oriPnt[intoriPntNum - 1];                                   //设置初始终点
            rePnt.Push(P0);                                                  //初始起点压入结果堆栈
            proPnt.Push(P1);                                                 //初始终点压入待检查的节点堆栈
            while (proPnt.Count != 0)                                        //当待检查的节点堆栈元素不为空时,执行循环;若元素为空,则说明压缩算法执行完毕。
            {                                                                //判断起点和终点之间是否还有其他节点,如果有则执行:
                if (P0.ID != P1.ID - 1)
                {
                    //设置一个线段距离最大的节点,并初始化它到线段的距离最小
                    Pnt maxPnt = new Pnt();
                    maxPnt.Dis = 0;
                    //循环线段起点和终点之间的所有其他节点,若距离大于maxPnt则代替它
                    for (int j = P0.ID + 1; j <= P1.ID - 1; j++)
                    {
                        Pnt tempPnt = new Pnt();
                        tempPnt     = oriPnt[j];
                        tempPnt.Dis = Distanct(P0, P1, tempPnt);//调用一个自定义函数Distanct,返回值为点到线段的距离。
                        if (tempPnt.Dis > maxPnt.Dis)
                        {
                            maxPnt = tempPnt;
                        }
                    }
                    //找出距离线段距离最远的节点以后,比较其距离和阈值的大小
                    //若大于阈值,则将节点压入到待检查的节点堆栈,并将该节点设置为线段的终点
                    if (maxPnt.Dis > intYuZhi)
                    {
                        P1 = maxPnt;
                        proPnt.Push(maxPnt);
                    }
                    //若小于阈值,则将终点设置为线段起点,并压入到结果堆栈中,并将待检查堆栈顶部的节点设置为线段终点
                    else
                    {
                        P0 = P1;
                        rePnt.Push(P0);
                        proPnt.Pop();
                        if (proPnt.Count != 0)
                        {
                            P1 = proPnt.Peek();
                        }
                    }
                }
                //判断起点和终点之间是否还有其他节点,如果没有则执行:
                else
                {
                    P0 = P1;
                    rePnt.Push(P0);
                    proPnt.Pop();
                    if (proPnt.Count != 0)
                    {
                        P1 = proPnt.Peek();
                    }
                }
            }
            //置换堆栈中节点的顺序
            while (rePnt.Count != 0)
            {
                proPnt.Push(rePnt.Pop());
            }
            //按照从线状要素起点到终点的顺序输出压缩后节点的信息
            textBox1.Text = textBox1.Text + "\r\n" + "压缩成功,压缩后线状要素节点为:" + proPnt.Count + "个;";
            textBox1.Text = textBox1.Text + "\r\n" + "----------------------------------------------------";
            textBox1.Text = textBox1.Text + "\r\n" + "压缩后保留的节点为:\r\n" + "点号(ID),X坐标,Y坐标";
            while (proPnt.Count != 0)
            {
                P0        = proPnt.Pop();
                strResult = strResult + "\r\n" + P0.ID + "," + P0.x + "," + P0.y;
            }
            textBox1.Text             = textBox1.Text + strResult;
            tabControl1.SelectedIndex = 1;
        }