ArcGIS API for Silverlight 使用GeometryService求解線與線的交點(二)


在前一篇的博文中說到了線與面交點的求解,其中使用的方法是利用GeometryService的Simplify+Intersect服務,通過獲得線與面的交點,間接的通過交線的端點得到線與面的交點。過程如下所示:

然而在上文中我們提到過一句,Geometry中的Intersect無法得到線與線的交點,盡管當我們使用Intersect求線與線相交時,可以返回相交的結果,但是無法獲取交點,因為Intersect求線與線交點返回的是一個Extent為null的線要素,我們無法將其用點在地圖上表達出來。

那么這里我們該怎么做呢?

這里我們用到了Geometry的另一個服務:TrimExtend(修剪擴展)

具體示例可參考:

http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#TrimExtend

關於TrimExtend功能的效果圖:

我們發現,使用TrimExtend之后網格水平線向右方向進行了衍生,並與線要素相交了,而位於河流下方的網格則被剪切掉了。

關於裁剪和延伸的方向(比如上圖是向右延伸,還可以設置向左延伸,或者雙向延伸等),可以通過CurveExtension屬性來設置,關於CurveExtension的屬性說明參看官方文檔:

http://help.arcgis.com/en/webapi/silverlight/apiref/api_start.htm

需要說明的是,TrimExtend返回的結果是線要素,而返回線要素的一端就是線要素與線要素的交點(僅當線要素相交時,從上圖我們會發現沒有相交的要素也被返回了,因此這里還需要進一步的篩選,具體將在后面說明)

通過以上分析,我們知道只要獲取返回線要素的端點就可以得到相交的結果。

下面是具體步驟:

1.構建網格(這里也可以使用某一圖層的線要素,本文采用自己構建網格,求網格與線要素相交的節點)

關鍵代碼:

a.根據兩個點構造一條直線

   public void CreateLine(MapPoint p1,MapPoint p2)
        {
            ESRI.ArcGIS.Client.Geometry.Polyline polyline = new ESRI.ArcGIS.Client.Geometry.Polyline();
            ESRI.ArcGIS.Client.Geometry.PointCollection pc=new ESRI.ArcGIS.Client.Geometry.PointCollection ();
            pc.Add(p1);
            pc.Add(p2);
            polyline.Paths.Add(pc);
            //記得對空間坐標系賦值,否則Simplify會出錯。
            polyline.SpatialReference = map1.SpatialReference;
            AddLineGraphic(polyline);  
        }

AddLineGraphic為自定義方法,作用是將線要素添加到圖層中,示例代碼如下:

  public void AddLineGraphic(ESRI.ArcGIS.Client.Geometry.Polyline polyline)
        {
            Graphic g = new Graphic()
            {
                Geometry = polyline,
                Symbol = LayoutRoot.Resources["LineSymbol"] as SimpleLineSymbol
            };
          
            glayer.Graphics.Add(g);
        }

這里用戶可以自定義網格的步長,根據繪制的矩形或多邊形范圍構建網格。

   public void CreateGrid(double xMin,double xMax,double yMin,double yMax,double xstep,double ystep)
        {
            //定義兩個Point,確定一條直線
            MapPoint mp1;
            MapPoint mp2;
            //由步長確定划分成多少份
            int Nx = Convert.ToInt32((xMax - xMin)/xstep);
            int Ny = Convert.ToInt32((yMax - yMin) / ystep);
            //構造豎直方向的線
            for (int i = 0; i <Nx+1; i++)
            {
                mp1=CreateMapPoint(xMin+i*xstep, yMin);
                //mp2=CreateMapPoint(xMin + i * xstep,yMax);
                mp2 = CreateMapPoint(xMin + i * xstep, yMin + Ny * ystep);
                CreateLine(mp1, mp2);
            }
            //構造水平方向的線
            for (int i = 0; i < Ny+1; i++)
            {
                mp1 = CreateMapPoint(xMin, yMin +i * ystep);
                mp2 = CreateMapPoint(xMin + Nx * xstep, yMin + i * ystep);
                //mp2 = CreateMapPoint(xMax, yMin + i * ystep);
                CreateLine(mp1, mp2);
            }
            //RectExtent為自定義的一種結構體,存儲每一次網格划分時的矩形范圍
            recExtent = new RectExtent()
            {
                Xmin = Convert.ToDouble((xMin).ToString("#0.000")),
                Xmax = Convert.ToDouble((xMin + Nx * xstep).ToString("#0.000")),
                Ymin = Convert.ToDouble((yMin).ToString("#0.000")),
                Ymax = Convert.ToDouble((yMin + Ny * ystep).ToString("#0.000"))
            };
        }
     

效果示意圖:

下面就通過TrimExtend服務來實現獲取交點的功能

2.調用TrimExtend功能

private void intersectCenterLineButton_Click(object sender, RoutedEventArgs e)
        {
            //存儲線要素的集合
            List<ESRI.ArcGIS.Client.Geometry.Polyline> polyLineListGrid = new List<ESRI.ArcGIS.Client.Geometry.Polyline>();
            List<ESRI.ArcGIS.Client.Geometry.Polyline> polyLineListriver = new List<ESRI.ArcGIS.Client.Geometry.Polyline>();

            if (glayer.Graphics.Count == 0 || flayer.Graphics.Count == 0)
            {
                MessageBox.Show("請確認輸入的線要素不為空");
                return;
            }
            //遍歷圖層的線要素
            foreach (Graphic g in glayer.Graphics)
            {
                polyLineListGrid.Add(g.Geometry as ESRI.ArcGIS.Client.Geometry.Polyline);
            }
            
            foreach (Graphic g in flayer.Graphics)
            {
                polyLineListriver.Add(g.Geometry as ESRI.ArcGIS.Client.Geometry.Polyline);
            }
            /*************************************
             * 被相交的圖層(在本文中只有一個要素,所以索引為0)
             * 第一個參數表示相交的要素,例如網格,因此是一個集合
             * 第二個參數表示被相交的要素,例如一條河流,因此是一個線要素,而不是要素的集合
             * 第三個參數表示延伸(剪切)的屬性
             *************************************/
            geometryService.TrimExtendAsync(polyLineListGrid, polyLineListriver[0], CurveExtension.NoExtendAtFrom);
        }

 接下來就是對結果進行處理,上面我們說過,所有交線的一個端點即為直線的交點。下圖是返回直線的結果(紅色線段即為結果),這里需要注意的是

使用TrimExtend功能時,CurveExtension屬性設置為NoExtendAtFrom,這樣網格就會從起點向右尋找格線的交點,沒有交點則向右延長,直到相交。

(1)交線的長度一定小於初始時繪制的網格的范圍,即

   水平方向的交線長度<|Xmax-Xmin|, Xmax,Xmin為網格X軸的最大與最小值。

   垂直方向的交線長度<|Ymax-Ymin|, Ymax,Ymin為網格Y軸的最大與最小值。

(2)針對於水平和垂直網格,交點的坐標始終是最小值(當是斜線的時候,可通過獲取交線的斜率,然后再求得交點)

知道了這兩點,我們實現起來就I叫容易了。下面是獲取結果的代碼:

    void geometryService_TrimExtendCompleted(object sender, GraphicsEventArgs e)
        {
            glayer.Graphics.Clear();
            MapPoint intersectPoint = null;

            foreach (Graphic g in e.Results)
            {
                g.Symbol = LayoutRoot.Resources["ResultsLineSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol;
                glayer.Graphics.Add(g);
                if (g.Geometry.Extent != null)
                {
                    /*recExtent結構體存儲了繪制矩形的范圍
                     * 這里通過比較返回結果中線段長度來判斷其是不是交線
                     * 同時本文繪制的網格是垂直和水平的,
                     * 所以交線的長度肯定小於繪制矩形的范圍(這里只需要判斷水平方向即可)
                     * 關於斜線的情況,判斷方法類似
                     */
                    if ((g.Geometry.Extent.XMax - g.Geometry.Extent.XMin) < (recExtent.Xmax - recExtent.Xmin))
                    {
                        intersectPoint = CreateMapPoint(g.Geometry.Extent.XMin, g.Geometry.Extent.YMin);
                        AddPointGraphic(intersectPoint);
                    }
                }
            }
        }
    

其中CreateMapPoint方法表示通過X,Y坐標構造一個點,AddPointGraphic表示將點添加到地圖中顯示。

 //由X,Y構造一個點
public MapPoint CreateMapPoint(double x,double y)
        {
            return new MapPoint(x, y);
        }

//將一個點添加到Layer中
 public void AddPointGraphic(ESRI.ArcGIS.Client.Geometry.MapPoint point)
        {
            Graphic g = new Graphic()
            {
                Geometry = point,
                Symbol = LayoutRoot.Resources["PointSymbol"] as SimpleMarkerSymbol,
            };

            glayer.Graphics.Add(g);
        }

這樣我們就求得了線與線的交點。

示例圖:

a.構造的網格線

 

 b.交點

總結:

本文使用TrimExtend來求解交點,過程是:獲取TrimExtend功能返回的線段,篩選出交線,然后獲得交線的端點,即為交點。本文講解了網格是水平和垂直時相交的情況,當線段是不規則的情況下,可以通過交線的斜率來確定交點。

 下一篇,將講解構造斜線網格來求交點,歡迎繼續關注。

(版權所有,轉載請標明出處)

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM