ARCGIS engine 定長且批量繪製線段的中垂線
阿新 • • 發佈:2019-01-23
由於研究的需要,本人需要將一段曲線按等距離打斷,分成固定長度的線段,並且按需要的長度繪製線段的中垂線。按照能不自己動手就堅決不動手的原則,我查閱了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; }