欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c# 基于GMap.NET實現(xiàn)電子圍欄功能(WPF版)

 更新時間:2021年03月09日 11:45:01   作者:源之緣  
這篇文章主要介紹了c# 基于GMap.NET實現(xiàn)電子圍欄功能(WPF版),幫助大家更好的理解和學習使用c#,感興趣的朋友可以了解下

前言 

GMap.NET是一個強大、免費、跨平臺、開源的.NET控件。分為WPF和winform版。GMap.NET的基本知識不做過多介紹,本文主要介紹如何使用該控件實現(xiàn)電子圍欄功能。

電子圍欄主要有兩個功能模塊:界面展示圍欄區(qū)域,判斷人員出入圍欄的邏輯。GMap.NET的WPF版本功能并不強大,實現(xiàn)一些復雜的功能就只能發(fā)掘WPF的潛力了。GMap.NET給我們提供了一個基本的平臺,必須熟練掌握WPF才能開發(fā)出復雜gis產(chǎn)品。

圍欄區(qū)域界面顯示

1 認識 GMapMarker

  GMapControl是地圖的主容器;地圖就是多個圖片拼接而來,這個圖片組成GMapControl的底圖。底圖之上點綴用戶自定義的控件。用戶自定義控件必須通過GMapMarker間接添加進來,看下面代碼:

GMapMarker maker = new GMapMarker(ptLatLng);
 //UserControlFence用戶自定控件
 _ctrlCurrentFence = new UserControlFence() { Marker = maker, MapCtrl = MainMap };
 _ctrlCurrentFence.FenceInfo = CreateFenceInfoModel();

 maker.Shape = _ctrlCurrentFence;
 this.MainMap.Markers.Add(maker);

GMapMarker 的定義也不復雜:

public class GMapMarker : INotifyPropertyChanged
{
    public object Tag;
 
    public GMapMarker(PointLatLng pos);
 
    public UIElement Shape { get; set; }
    public PointLatLng Position { get; set; }
    public GMapControl Map { get; }
    public Point Offset { get; set; }
    public int LocalPositionX { get; }
    public int LocalPositionY { get; }
    public int ZIndex { get; set; }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    public virtual void Clear();
    protected void OnPropertyChanged(string name);
    protected void OnPropertyChanged(PropertyChangedEventArgs name);
}

一個GMapMarker關聯(lián)一個gps坐標,同時可以顯示一個控件(Shape );為什么在Shape外面包含一個marker?maker主要功能就是將控件釘?shù)紾MapControl的一個點。當?shù)貓D移動時,maker會做相應的移動,maker移動會帶動shape移動。所以,我們只管把shape內(nèi)部處理好就行了,不用管地圖移動。maker的作用不大,并不能幫我們實現(xiàn)復雜的功能;Shape才是我們施展拳腳的地方。

2 用戶控件實現(xiàn)畫圖

在控件中UserControlFence實現(xiàn)電子圍欄的繪制,該控件會關聯(lián)到maker的shape。UserControlFence控件以Grid(name為gridRoot)布局;WPF的Path可以實現(xiàn)任意圖像的繪畫,首先要將Path加入到Grid。我們的輸入是多個gps點坐標,怎么能轉換成Path上各個點坐標? 這需要經(jīng)過多次轉換;

Point ToCtrlPoint(PointLatLng gpsPoint)
  {
   //轉換成GMap.NET控件坐標
   GPoint ptOfMapCtrl = MapCtrl.FromLatLngToLocal(gpsPoint);

   //GMap.NET控件坐標要轉換成 控件相對于直接父面板的坐標
   Point ptToMapCtrl2 = new Point(ptOfMapCtrl.X, ptOfMapCtrl.Y);
   //轉成屏幕坐標
   Point ptOfScreen = MapCtrl.PointToScreen(ptToMapCtrl2);
   //轉換成相對于gridRoot的坐標
   Point ptOfParentPanel = gridRoot.PointFromScreen(ptOfScreen);

   return ptOfParentPanel;
  }

轉換過程就是:相對于Map控件坐標-->屏幕坐標-->相對于Grid的坐標。因為Path是Grid的Child,最后的坐標也是相對于Grid的坐標。用該坐標繪制Path,就是電子圍欄的區(qū)域;

Path的Data是Geometry,生成Geometry函數(shù)如下:

private PathGeometry CreatPath()
  {
   if (_listPoints.Count <= 1)
   {
    PathRouteLine.Data = null;
    return null;
   }

   List<Point> listPt = ListWndPoint;

   PathFigure pathFigure = new PathFigure();
   pathFigure.StartPoint = listPt[0]; //起始點
   pathFigure.IsClosed = true;

   for (int i = 1; i < listPt.Count; i++)
   {
    //加入線段
    LineSegment line = new LineSegment() { Point = listPt[i] };
    pathFigure.Segments.Add(line);
   }

   PathGeometry geometry = new PathGeometry();
   geometry.Figures.Add(pathFigure);
   return geometry;
  }

這樣就完成電子圍欄的區(qū)域繪制。還有一點要注意:當?shù)貓D縮放時,必須重新繪制。地圖縮放比例不同,繪制區(qū)域大小也會改變(形狀不會變)。只需要監(jiān)視地圖控件的事件 public event MapZoomChanged OnMapZoomChanged;就行。

出入電子圍欄區(qū)域判斷

該判斷邏輯有多種實現(xiàn)方法,下面逐一介紹;

1 利用WPF的輔助函數(shù) VisualTreeHelper.HitTest

 通過判斷gps點坐標是否在控件內(nèi)來判斷。gps坐標先要轉成控件點坐標(轉換函數(shù)見前文)。函數(shù)實現(xiàn)比較簡單;

private bool IsInFence(PointLatLng gpsPoint)
  {
   if (_listPoints.Count <= 2)
    return false;
   Point ptWnd = ToCtrlPoint(gpsPoint);

   HitTestResult result = VisualTreeHelper.HitTest(gridRoot, ptWnd);
   if (result == null || result.VisualHit==null)
    return false;

   bool hit = result.VisualHit == PathRouteLineInner;
   return hit;
  }

2 通過GraphicsPath、Region實現(xiàn)

 這是System.Drawing下的一組類,屬于微軟早期的類庫;該類的點坐標還是float型,精度不高。對于gps坐標我先做了放大處理,如果不做處理誤差會很大。

private bool IsInFence2(PointLatLng gpsPoint)
  {
   double rate = 100000; //由于float精度問題。對坐標放大處理,否則誤差會很大。
   System.Drawing.Drawing2D.GraphicsPath pointPath = new System.Drawing.Drawing2D.GraphicsPath();
   System.Drawing.PointF[] points = _listPoints.Select(o => new System.Drawing.PointF((float)(o.Lng * rate), (float)(o.Lat * rate))).ToArray();
   pointPath.AddLines(points);
   pointPath.CloseFigure();
    
   System.Drawing.Region region = new System.Drawing.Region(pointPath);
   System.Drawing.PointF ptHit = new System.Drawing.PointF((float)(gpsPoint.Lng * rate), (float)(gpsPoint.Lat * rate));
   bool visible = region.IsVisible(ptHit);
   return visible;
  }

3 直接根據(jù)點坐標計算

 理論上這種方式效率是最高的,并且不依賴界面控件。但是這種方法不是微軟提供的,準確性還需要驗證。下面的函數(shù)是從網(wǎng)上找的,我對此計算結果做了驗證,與前兩種計算方法的結果一致的。

private bool IsInFence3(PointLatLng gpsPoint)
  {
   int count = _listPoints.Count;
   if (count < 3)
   {
    return false;
   }

   bool result = false;
   for (int i = 0, j = count-1; i < count; i++)
   {
    var p1 = _listPoints[i];
    var p2 = _listPoints[j];

    if (p1.Lat < gpsPoint.Lat && p2.Lat >= gpsPoint.Lat || p2.Lat < gpsPoint.Lat && p1.Lat >= gpsPoint.Lat)
    {
     if (p1.Lng + (gpsPoint.Lat - p1.Lat) / (p2.Lat - p1.Lat) * (p2.Lng - p1.Lng) < gpsPoint.Lng)
     {
      result = !result;
     }
    }
    j = i;
   }
   return result;
  }

后記

電子圍欄區(qū)域繪制方法與軌跡回放、測距等處理有類似之處;GMap.Net為我們做的工作并不多,關鍵是要掌握處理這一類問題的精髓,做到舉一反三,許多問題就會迎刃而解。

以上就是c# 基于GMap.NET實現(xiàn)電子圍欄功能(WPF版)的詳細內(nèi)容,更多關于c# GMap.NET實現(xiàn)電子圍欄的資料請關注腳本之家其它相關文章!

相關文章

最新評論