1. 程式人生 > >ARCGIS engine 定長且批量繪製線段的中垂線

ARCGIS engine 定長且批量繪製線段的中垂線

            由於研究的需要,本人需要將一段曲線按等距離打斷,分成固定長度的線段,並且按需要的長度繪製線段的中垂線。按照能不自己動手就堅決不動手的原則,我查閱了ARCGIS關於處理線要素的工具,發現只有等距離打斷曲線的工具,但沒有繪製線段中垂線的工具。哎,無奈之下,只能自己編寫程式了。寫程式前,先弄明白繪製中垂線的基本流程。實現工具:visual studio 2010+ARCGIS engine10.1 。資料:等距離打斷的曲線圖層。依據當前的工具和資料,我制定了完成任務的基本流程:

          AE載入向量資料的方法——獲取線段的端點(有些線段可能是曲線,因此計算的是線段兩點連線的中垂線,我是沒想出其他好的方法

。)——計算中垂線的兩點(由於要求中垂線是定長的,我選擇了以線段兩點中點為準,求出定長中垂線上另一點)——要素編輯並存儲——完成

         看了下流程,難點在於計算中垂線的兩點:本人選擇了一種笨方法,方程求解。基本過程如下:1 利用已知線段的兩個端點,求出線段中點的座標,這個很簡單。 2 求出線段端點連線的斜率,中垂線的斜率也就出來了,利用中點就可以求出中垂線的線性表示式,然後結合兩點距離公式算出定長點的座標(有兩個點哦,我選擇了這兩個點來繪製中垂線的)

        基本思路如上,下面就是貼程式碼時間了:首先貼出核心程式碼——計算中垂線的兩點的函式

  /// <summary>
        /// 依據輸入兩點來計算輸入兩點的中位線的兩點
        /// </summary>
        /// <param name="inpoint1"></param>
        /// <param name="inpoint2"></param>
        /// <param name="outpoint1"></param>
        /// <param name="outpoint2"></param>
        private void CaculateMiddleLinePoints(IPoint inpoint1,IPoint inpoint2,out IPoint outpoint1,out IPoint  outpoint2)
        { 
            //k
            double k = (inpoint2.Y - inpoint1.Y) / (inpoint2.X - inpoint1.X);
            //middle point for inpoint1 and inpoint2
            IPoint middlePoint = new PointClass();
            middlePoint.X = (inpoint1.X + inpoint2.X) / 2;
            middlePoint.Y = (inpoint1.Y + inpoint2.Y) / 2;
            double k01=-1/k;
            double b01 = middlePoint.Y -k01 * middlePoint.X;
            //caculate another point of middle line

            //
            double b1 =2*(-middlePoint.X + k01 * b01- k01 * middlePoint.Y);
            double a1 = 1 + k01 * k01;
            // 其中最後的一個數值5000代表的是中點到另一個點的距離,可以依據自己的需求來設定,我直接寫成了5000m
            double c1 = middlePoint.X * middlePoint.X + b01 * b01-2 * b01 * middlePoint.Y + middlePoint.Y * middlePoint.Y - 5000 * 5000;
            //到中點距離為5000的有兩個點,
            IPoint p1 = new PointClass();
            IPoint p2 = new PointClass();
            
            //如果無解則退出
            double delta=b1 * b1 - 4 * a1 * c1;
            if (delta < 0)
            {
                
                outpoint1 = null;
                outpoint2 = null;
                return;
            }
            p1.X = (-b1 + Math.Sqrt(delta )) / (2 * a1);
            p1.Y = k01 * p1.X + b01;

            p2.X = (-b1 - Math.Sqrt(delta)) / (2 * a1);
            p2.Y = k01 * p2.X + b01;

            //
            outpoint1 = p1;
            outpoint2 = p2;
          
        }
                計算出了中垂線的兩點,下面就簡單了,就是新增要素的過程,具體如下:
 private void button2_Click(object sender, EventArgs e)
        {
            button2.Enabled = false;
            //獲取儲存中位線的shp儲存檔案
            string targetLayerPath = @"d:\data\";
            string filename = "MiddleLine.shp";
            IWorkspaceFactory myWorkspacefac = new ShapefileWorkspaceFactoryClass();
            IFeatureWorkspace myFeatureworkspace = (IFeatureWorkspace)myWorkspacefac.OpenFromFile(targetLayerPath, 0);
            IFeatureClass targetFeatureclass = myFeatureworkspace.OpenFeatureClass(filename);
            //啟動編輯
            IWorkspaceEdit workspaceEdit=(targetFeatureclass as IDataset ).Workspace as IWorkspaceEdit;
            workspaceEdit.StartEditing(true);
            workspaceEdit.StartEditOperation();
            //快速查詢資料
            IQueryFilter mQueryFilter = new QueryFilterClass();
            IFeatureCursor mFeatureCursor =  lineLayer.Search(mQueryFilter, false);
            IFeature feature = mFeatureCursor.NextFeature();
            //提示處理進度
            Form2 frmTip = new Form2();
            frmTip.Show();
            frmTip.TopMost = true;
            System.Windows.Forms.Application.DoEvents();
            int i = 0;
            int featureCount = lineLayer.FeatureClass.FeatureCount(null);

            while (feature != null)
            {
                IPolyline line = feature.Shape as IPolyline;
                IPoint startPoint = line.FromPoint;
                IPoint endPoint = line.ToPoint;
                //計算中位線的兩點座標
                IPoint sMiPoint=new PointClass();
                IPoint eMIPoint=new PointClass();
                CaculateMiddleLinePoints(startPoint, endPoint,out sMiPoint,out eMIPoint);
                if (sMiPoint == null || eMIPoint == null)
                { 
                    string s=i.ToString();
                    MessageBox.Show(s);
                    return;
                    Application.Exit();
                }
                IPolyline miLine = new PolylineClass();
                miLine.FromPoint = sMiPoint;
                miLine.ToPoint = eMIPoint;
                IFeature addFeature = targetFeatureclass.CreateFeature();
                addFeature.Shape = miLine as IGeometry;
                addFeature.Store();
                //搜尋下一要素
                feature = mFeatureCursor.NextFeature();
                 
                //提示處理資訊
                i++;
                double leftcount = featureCount - i;
                frmTip.label1.Text = "請稍後,目前還剩 " + leftcount.ToString() + " 個要素未處理!";

            }
            //退出編輯狀態
            workspaceEdit.StopEditOperation();
            workspaceEdit.StopEditing(true );
            
            //處理完畢,退出提示
            frmTip.Close();
            frmTip.Dispose();

            button2.Enabled = true;
        }
                哈哈,大功告成了!貼下我的結果圖