本文章是由機器翻譯。

SQL Server 和 MapPoint

搭配運用 MapPoint 2010 與 SQL Server 空間

Eric Frost

下載代碼示例

在 Bing Maps 之後,Microsoft 提供了一些非常突出的地理空間技術,其中兩種是 Microsoft MapPoint 2010 和 SQL Server 2008 R2 中的空間功能。然而,儘管 SQL Server 是存儲地理空間資料的理想之選,而 MapPoint 也是一種優秀的地理空間檢視器,但它們之間的通信並不如預想中的那麼容易。

本文將演示如何從 SQL Server 讀取點和多邊形物件並在 MapPoint 中進行呈現。還將演示如何使用 Visual Studio 2010 中包含的 Entity Framework 4.0 將點和多邊形寫回 SQL Server。

為便於說明,文中將使用一家芝加哥公司“Al’s Beef”的餐廳位置和假設的交易區。在零售分析和建模過程中,可以使用不同參數定義交易區並可將其用於不同目標。通常將其定義為圍繞某個店鋪的最社區域,其中包含了滿足特定閾值的地區,例如,50% 或 75% 的客戶居住或工作的地區。本文中使用的所有交易區均使用 MapPoint 的“創建駕車時間區”功能創建,因此代表的是根據駕車時間所劃定的假設交易區。

作為只有幾十家店鋪的連鎖店,Al’s Beef 是一家規模相對較小的企業,但是,在此所使用的概念和技術,同樣也適用于具有上千家連鎖店的大型零售商以及其他行業和應用。

示例代碼和“Al’s Beef”資料集(SQL 腳本格式)均可從 code.msdn.microsoft.com/mag201009Spatial 下載。

雖然本文並非過於技術化的文章,沒有涉及最新語言或技術的複雜層面,但仍可用作常用 Microsoft 技術的有用組合的實用操作方法指導。文中說明了幾個難點,包括實體框架不能直接理解 geography 物件以及 SQL Server Spatial 要求多邊形必須為逆時針方向而 MapPoint 並無此要求。希望本文對於資深但由於缺少相關經驗而不願意進入地理空間領域的開發人員能夠有所説明,同時能向 MapPoint 開發人員演示如何成功利用 SQL Server 2008 R2。

設置資料庫

為了按照本文中的代碼示例操作,請先下載 SQL 腳本並在 SQL Server 中運行以設置資料庫和物件。資料存儲在 SQL Server 資料庫中,名為“Corporate”,包括一張表、一個視圖和一個存儲過程。Al’s Beef 的位置存儲在名為“Locations”的表中(參見圖 1)。

圖 1 示例資料庫中包括的表和視圖

這包括店鋪的位址、屬性(例如,是否免下車?)以及位置點 geography 資料類型。假設交易區多邊形以 geography 資料類型也存儲在“Locations”表的名為 TradeArea 的欄位中。

vLocations 視圖將點和多邊形 geography 欄位提供給可由實體框架理解和讀取的資料類型。

點 geography 欄位可分解為緯度和經度欄位,並作為 varbinary 欄位傳遞回用戶端。這是由於實體框架無法直接處理 geography 資料類型,但可以處理 varbinary 欄位。應用程式隨後可以將這些內容轉換回 geography 物件。

以下為存儲過程 uspAddLocation,故名思義,它用於從 MapPoint 將新位置插入回 SQL Server 中:

CREATE VIEW [dbo].[vLocations]
AS
SELECT LocID,Location.Long As Longitude,
       Location.Lat As Latitude,
       CAST(Location AS VARBINARY(MAX)) AS Location,
       Locations.TradeArea.STAsText() As TradeAreaWKT,
       CAST(TradeArea AS VARBINARY(MAX)) AS TradeArea
FROM Locations

我們稍後再討論此內容。

設置應用程式

此專案是集成了 MapPoint 控制項的 C# Windows 表單應用程式。該控制項包括在 MapPoint 2010 中,要使用該控制項,必須安裝 MapPoint 2010 完整版。使用按鈕遍歷記錄可導航到記錄,並可顯示店鋪及其交易區。也可通過按一下店鋪的圖釘圖示來選擇店鋪。表單還提供了用於將交易區顯示為凸球面的核取方塊和用於添加新位置的按鈕。預設情況下,應用程式按照多邊形在資料庫中的存儲樣式顯示它(參見圖 2)。

圖 2 Al’s Beef 應用程式,按資料庫中的定義顯示芝加哥高地店鋪和地域

如果選中了“以凸球面樣式查看交易區”核取方塊,則將會使用線條(凸球面)環繞交易區,類似于使用橡膠帶圍起多邊形(參見圖 3)。

圖 3 芝加哥高地店鋪,使用凸球面圍起了圖 2 中所示地域

在顯示地圖之前,需要添加指向資料庫表和視圖的實體資料物件。要建立實體資料物件,請在 Visual Studio 解決方案資源管理器中按右鍵應用程式,然後轉到“添加 | 新建項 | Visual C# 項 | ADO.NET 實體資料模型”。按一下“添加”並選擇“從資料庫生成”。在“選擇資料庫物件”對話方塊中,選擇表 Locations 和視圖 vLocations。按一下“完成”後,該嚮導將創建物件並生成連接到資料庫所需的代碼。

要將 MapPoint 2010 控制項添加到 Windows 表單,則必須先將 MapPoint COM 控制群組件添加到 Visual Studio 工具箱。COM 不是最流行的技術,但一直是 Windows 生態系統中的一個重要部分。包括 MapPoint 在內的許多應用程式僅通過 COM 介面實現 API,並且 Visual Studio 仍將持續提供對 COM 的支援。

打開 Visual Studio 工具箱,然後在“常規”部分中,按右鍵並選擇“選擇項”。轉到“COM 元件”選項卡,然後選擇“Microsoft MapPoint Control 17.0”。MapPoint Control 17.0 即為 MapPoint 2010(北美或歐洲地區)。也可使用較早版本的 MapPoint(2002 版之前),但需要對名稱稍作改動(例如,工具列名稱和符號識別字)。

在 AxInterop.MapPoint 和 Interop.MapPoint 程式集上,將“嵌入式交互操作類型”屬性設置為 False,並將“複製本地”設置為 True。現在可以將 MapPoint 控制項拖動到表單上並在應用程式中使用。

初始化 Map 表單:載入 MapPoint

Map 表單聲明瞭多個成員變數,包括與實體框架的資料庫連接、店鋪資訊清單以及將從視圖中讀取的店鋪地理資訊並行清單。變數 curLoc 跟蹤應用程式中的當前店鋪 ID,objMap 用於引用 MapPoint 控制項的 map 物件,如此處所示:

namespace AlsBeef
{
 public partial class Map : Form
 {
  CorporateEntities db;
  List<Location> locationList;
  List<vLocation> vlocationList;
  int curLoc = -1;    // <0 indicates 'not set'
  MapPoint.Map objMap;
  MapPoint.Symbol objSymb;
  ...

創建表單之後,將調用方法 CreateNewMapObject 以初始化地圖控制項並使用預設北美地圖範本打開新地圖。 此時已經設置了工具列、定義了 objMap 並且已關閉興趣點,以避免造成地圖混亂(參見圖 4)。 舉例而言,“興趣點”是 MapPoint 預定義的場所、餐廳和劇院。

图 4 创建窗体

public Map()
{
 InitializeComponent();
 CreateNewMapObject();
}


private void CreateNewMapObject()
{
  MPctrl.NewMap(GeoMapRegion.geoMapNorthAmerica);
  object barObj = "advanced";
  MPctrl.Toolbars.get_Item(refbarObj).Visible = true;
  MPctrl.Toolbars.LargeToolbarButtons = false;
  objMap = MPctrl.ActiveMap;
  // Make sure all points of interest are turned off
  objMap.PlaceCategories.Visible = MapPoint.GeoTriState.geoFalse;
}

表單的 Load 方法填充店鋪資訊的兩個清單。 locationList 包含所有常規的非地理資訊,vlocationList 則讀取由資料庫視圖轉換的地理欄位:

private void Map_Load(object sender, EventArgs e)
{
 db = new CorporateEntities();
 locationList = new List<Location>();
 vlocationList = new List<vLocation>();

 ObjectQuery<Location> locationQuery =
  db.Locations;
 ObjectQuery<vLocation> vlocationQuery =
  db.vLocations;

 locationList = locationQuery.ToList();
 vlocationList = vlocationQuery.ToList();

 InitMapSymb();
 InitMapPins();
 SetLocation(0);
}

最後兩行則通過初始化地圖來實際啟動應用程式。 它們會為每個店鋪位置添加圖釘 (InitMapPins),並且定位地圖和表單控制項以指向第一個店鋪位置的資料 (SetLocation)。

向地圖添加圖釘

InitMapPins 方法中的情況更有趣:

private void InitMapPins()
  {
    MapPoint.Pushpin objPin = null;
    for (int i = 0; i < locationList.Count;
     i++)
    {
     MapPoint.Location objLoc =
      objMap.GetLocation(vlocationList[i].
Latitude.Value,
      vlocationList[i].Longitude.Value);
     objPin = objMap.AddPushpin(objLoc,   
      locationList[i].Name);
     objPin.Symbol = 145; // Red fork and knife
                         // (food, restaurant)
   }
  }

迴圈遍歷 locationList 以檢索由視圖計算和公開的緯度和經度值。 這用於創建 MapPoint Location 物件,然後使用這些物件創建地圖圖釘(MapPoint Pushpin 物件)。 店鋪名稱用於 PushpinName 屬性,該屬性隨後用於搜索和定位地圖。 使用 MapPoint 內置的紅色餐廳圖釘符號(符號 #145)來表示圖釘。 有關 MapPoint 2010 內置符號的完整清單,請參見 mapping-tools.com/info/pushpins/pushpins_2010.shtml。 本頁還連結到了 MapPoint 較早版本中的圖釘清單。

定位到目前記錄並將多邊形添加到地圖中

使用 IncDecLocation 和 SetLocation 方法選擇和顯示新記錄。 IncDecLocation 只是在當前位置 (curLoc) 應用增量 (cnt) 並將此新記錄位置傳遞到 SetLocation:

private void IncDecLocation(int cnt = 0)
{
 // Apply the increment/decrement, wrapping around if necessary
 int newLoc = (curLoc + cnt + locationList.Count) % locationList.Count;

 SetLocation(newLoc);
}

SetLocation 常式是應用程式的作業主力。 SetLocation 選擇新記錄位置並在地圖上顯示它。 SetLocation 還從以前的圖釘(如果有)上刪除突出顯示標記,並從地圖上清除所有以前的交易區多邊形(參見圖 5)。

圖 5 SetLocation 常式是應用程式的作業主力

private void SetLocation(int newLoc)
{
  MapPoint.Pushpin objPin = null;

  // Unhighlight previous pushpin
  If (curLoc>= 0)
  {
    objPin = (MapPoint.Pushpin)
     objMap.FindPushpin(locationList[curLoc].Name);
    objPin.Highlight = false;
  }

  // Clear all previous shapes
  while(objMap.Shapes.Count> 0)
  {
    objMap.Shapes[1].Delete();
  }
 

  // Set the new location
  curLoc = Math.Min( Math.Max(newLoc,0), locationList.Count-1);

  objPin = (MapPoint.Pushpin)
   objMap.FindPushpin(locationList[curLoc].Name);
  objMap.Location = objPin.Location;

...

接下來的部分會有一些棘手。 首先,應用程式檢查“以凸球面樣式查看交易區”核取方塊的狀態。 如果未選中該核取方塊,則將採用定義多邊形的 Well-Known Text (WKT) 字串並將其傳遞給自訂 RenderPolygon 方法,以將其解析和呈現為地圖上的多邊形。

如果選中了該核取方塊,則提取地域多邊形的 varbinary 物件並使用 System.IO.MemoryStream 類和 BinaryReader 方法將其轉換為 geography 物件。 STConvexHull 是 SQL Server 2008 中包括的方法之一;您可以用它來修改 geography 或 geometry 資料的實例。 需特別注意的是,STConvexHull 僅可用於 geometry 資料類型。 SQL Server 的 geometry 和 geography 資料類型之間的區別另有詳述,但目前所需要考慮的是,geometry 資料在(2 維歐幾裡得)笛卡爾平面中定義,而 geography 資料則使用球形坐標系統(資料、投射、本初子午線和度量單位)投射到球形地球表面。

交易區使用 geography 欄位類型存儲在資料庫中,然後由視圖轉換為 varbinary。 必須將此物件讀取到 geography 物件中,然後將該 geography 物件轉換為 geometry 物件以運行 STConvexHull 方法。

由於涉及到的區域較小,由 STConvexHull 在(平面)geometry 物件上執行的計算,實際上與對實際球形 geography 物件的凸球面計算得到的結果相同。

在 SetLocation 的下一部分中,原始交易區以細黑線繪製,而凸球面則以粗紅線呈現。 代码如图 6 所示。

圖 6 繪製原始交易區和凸球面

...
// Draw trade area
if (checkBox1.Checked == false)
{
 RenderPolygon(vlocationList[curLoc].TradeAreaWKT);
}
else
{
  // Need to add C:\Program Files\Microsoft SQL
  // Server\100\SDK\Assemblies\Microsoft.SqlServer.Types.dl
  // to references
  SqlGeographyTradeAreaGeog = new SqlGeography();
  using (var stream = new
   System.IO.MemoryStream(vlocationList[curLoc].TradeArea))
  {
   using (var rdr = new System.IO.BinaryReader(stream))
   {
    TradeAreaGeog.Read(rdr);
   }
  }
  SqlGeometry TAConvexHullGeom = new SqlGeometry();
  TAConvexHullGeom =  
   SqlGeometry.STPolyFromText(TradeAreaGeog.STAsText(), 4326);
  TAConvexHullGeom = TAConvexHullGeom.STConvexHull();
  RenderPolygon(TradeAreaGeom.ToString(), 3355443, 0); // Gray80
  RenderPolygon(TAConvexHullGeog.ToString());
}
...

那麼,此 WKT 字串外觀如何?RenderPolygon 對其採取什麼操作? 您已看到了结果(在图 2 3 中)。 接下來進行深入討論。

WKT 是一種開放地理空間聯盟 (OGC) 標準格式,用於格式化文字格式的地理空間向量資料。 WKT 多邊形字串外觀如下所示(已大幅簡化):

POLYGON ((-111.918823979795 33.6180476378649, -111.91810682416 33.6096635553986, -111.911686453968 33.6078672297299, -111.907403888181 33.599476357922, -111.907403888181 33.6060674674809, -111.903121406212 33.6060674674809))

單詞“POLYGON”位於使用兩組括弧括起的座標清單之前。 單個座標對之間使用逗號分隔。 使用 MapPoint AddPolyLine 方法在地圖上繪製多邊形,並將其添加到 MapPoint 形狀集合中。 這會將 MapPoint Location 物件的陣列用作參數。 將 WKT 字串轉換為 Location 物件陣列需要六行代碼。 為此,RenderPolygon 將除去“POLYGON”首碼和括弧,然後使用逗號分隔符號將字串拆分為座標。 接下來將單個座標解析為一對用於創建 MapPoint Location 物件的雙精度數(經度,緯度)。 然後將生成的 Location 物件陣列傳遞到 AddPolyline 以創建新多邊形。

RenderPolygon 帶有用於描述顏色和線條粗細的其他參數(參見圖 7)。

圖 7 RenderPolygon 方法

private void RenderPolygon(string polystring, 
 int forecolor = 128, int weight = 3)
{
  polystring = polystring.Replace("POLYGON ((", "");
  polystring = polystring.Replace("))", "");
  string[] stringList = polystring.Split(',');
  MapPoint.Location[] objLoc = 
   new MapPoint.Location[stringList.Count()];
  for (int i = 0; i <stringList.Count(); i++)
  {
   string[] coords = stringList[i].Trim().Split(' ');
   objLoc[i] = objMap.GetLocation(Convert.ToDouble(coords[1]),  
    Convert.ToDouble(coords[0]), 0);
  }
  MapPoint.Shape objShape;
  objShape = objMap.Shapes.AddPolyline(objLoc);
  objShape.Line.ForeColor = forecolor;
  objShape.Line.Weight = weight;
}

更完整的 RenderPolygon 可能會需要使用其他參數,這取決於是否填充形狀、填充顏色、形狀名稱(可以分配到形狀的內部字串)和 zOrder(將形狀定位到道路和其他形狀之前或之後)。

使用者和程式都可以在 MapPoint 地圖上放置圖形和注釋。 MapPoint 總共支援使用 40 種不同的顏色進行注釋。 雖然程式設計介面支援標準的 3 位元組 RGB(16,777,216 種)顏色,實際上這些數位僅提供了指定要使用的顏色的有用方式。 有關 MapPoint 支援的 40 種顏色,請參見 mapping-tools.com/info/pushpins/colors.shtml

以前,這種限制有助於高效更新圖像,但現在主要用於説明確保顏色各不相同,從而提高地圖清晰度。

我們現在來介紹 SetLocation 的最後一部分(參見圖 8)。

圖 8 SetLocation 的最後一部分

...
// Reset zoom level
   objMap.Altitude = 30;
   objPin.Highlight = true;

   Double distance;
   distance = 
     NearestLocation(curLoc) * 0.000621371192; //convert to miles

   label1.Text = "ID: " + locationList[curLoc].LocID.ToString();
   label2.Text = locationList[curLoc].Name + " - " +  
     locationList[curLoc].Format;
   label3.Text = locationList[curLoc].Address + ", " + 
     locationList[curLoc].City + ", " + locationList[curLoc].State;
   label4.Text = "Distance to next closest store: " + 
     String.Format("{0:#,0.0}", distance) + " miles";

  }

private double NearestLocation(int curLoc)
{

 SqlGeography AllLocations = new SqlGeography();
  SqlGeography CurLocation = new SqlGeography();
  for (int i = 0; i <locationList.Count; i++)
  {
    SqlGeography TempLocation = new SqlGeography();
    using (var stream = new 
     System.IO.MemoryStream(vlocationList[i].Location))
   { 
     using (var rdr = new System.IO.BinaryReader(stream))
     {
       TempLocation.Read(rdr);
     }
   }
   if (i == curLoc)
   {
     CurLocation = TempLocation;
   }
   else
   {
     AllLocations = AllLocations.STUnion(TempLocation);
   }
  }
  return (Double)AllLocations.STDistance(CurLocation); //meters
}

這突出了新圖釘、設置縮放級別(使用 Map 物件的“高度”屬性),報告店鋪資訊(從 locationList 陣列)並查找與最近店鋪位置的距離。

此距離由 NearestLocation 計算。 這將遍歷位置並使用 SQL Server Spatial STUnion 方法將 Location geography 點結合到 MultiPoint geography 實例中。 當前店鋪位置為例外,將跳過,否則距離始終為零英里! 應用程式然後使用 STDistance 方法計算當前店鋪位置與 MultiPoint geography 實例間的距離(米)。 STDistance 報告的與某個 MultiPoint 的距離,是與 MultiPoint 中任意元件點的最短距離。

用於添加新地點位置的按鈕將從地圖中刪除任意交易區多邊形,然後將滑鼠指標更改為十字游標:

private void button1_Click(object sender, EventArgs e)
{
  // Clear all previous shapes
  while(objMap.Shapes.Count > 0)
  {
    objMap.Shapes[1].Delete();
  }
  MPctrl.MousePointer = MapPoint.GeoPointer.geoPointerCrosshair;
}

為了處理 MapPoint 事件,表單要求在表單設計器中定義事件處理常式。 可以使用表單設計器添加事件,也可以手動將其添加到 Map.Designer.cs。 處理常式將被添加到兩個 MapPoint 事件中:SelectionChange 和 BeforeClick,如圖 9 所示。

圖 9 將處理常式添加到 MapPoint 事件

// 
// MPctrl
// 
this.MPctrl.Enabled = true;
this.MPctrl.Location = new System.Drawing.Point(13, 13);
this.MPctrl.Name = "MPctrl";
this.MPctrl.OcxState = 
  ((System.Windows.Forms.AxHost.State)
  (resources.GetObject("MPctrl.OcxState")));
this.MPctrl.Size = new System.Drawing.Size(674, 389);
this.MPctrl.TabIndex = 0;
this.MPctrl.SelectionChange += 
  new AxMapPoint._IMappointCtrlEvents_SelectionChangeEventHandler
 (this.MPctrl_SelectionChange);
this.MPctrl.BeforeClick += 
  new AxMapPoint._IMappointCtrlEvents_BeforeClickEventHandler
  (this.MPctrl_BeforeClick);

SelectionChange 事件用於檢測使用者是否選擇了圖釘。 這可以隨後用於將目前記錄移到此圖釘記錄。 圖 10 展示了事件處理常式的實現。

圖 10 實現 SelectionChange 事件處理常式

private void MPctrl_SelectionChange(object sender,  
 AxMapPoint._IMappointCtrlEvents_SelectionChangeEvent e)

{
  // Has the user just selected a pushpin?
if (e.pNewSelection is MapPoint.Pushpin)
  {
    MapPoint.Pushpin ppin = e.pNewSelection as MapPoint.Pushpin;

    // Find the corresponding location object, and select it
    for (int iloc = 0; iloc < locationList.Count; iloc++)
    {
      if (locationList[iloc].Name == ppin.Name)
      { // Found it: select, and move to it
        SetLocation(iloc);
        break;
      } 
    } 
  } 
}

這將檢查新選中的物件,在本例中為圖釘。 然後可以對本地 locationList 執行簡單搜索以查找匹配記錄。 MapPoint 圖釘可以具有重複名稱,因此,此代碼假定所有位置記錄(從而也就是圖釘)具有唯一名稱。 如果不能依靠此方法,還可以比較地理座標。

地圖的 BeforeClick 事件處理常式在“添加新店鋪位置”功能中使用。 處理常式進行檢查以確定滑鼠指標是否為十字游標,即使用者是否嘗試插入新地點位置。 這樣,MapPoint 在指標不是十字游標時仍處理按一下事件。 如果滑鼠指標是十字游標,則程式捕獲按一下操作,並在滑鼠指標位置使用紅色餐廳符號添加新圖釘。 此時,為了簡化過程,使用者不必繪製交易區,程式將使用 MapPoint AddDrivetimeZone 方法圍繞新地點生成假設(基於駕車時間)交易區。

為了將此形狀移到 SQL Server 中,首先將形狀分解為頂點,然後可以將頂點轉換為多邊形 WKT(文本)定義。 這會隨後寫入 SQL Server。

要將點和多邊形傳遞回 SQL Server 並更新 geography 列,不能使用實體框架支援的普通存儲過程,這是因為它們不支援 geography 資料類型。 但是,由於 Entity Framework 4.0 現在支援執行任意存儲過程,我們可以將存儲過程導入並作為普通函數執行。

此代碼將設置參數,然後執行 uspAddLocation 存儲過程:

object[] parameters =
{   
  new SqlParameter("Latitude",objLoc.Latitude),
  new SqlParameter("Longitude",objLoc.Longitude),
  new SqlParameter("PolyWKT",PolyWKT)
};

var retValue = db.uspAddLocation(objLoc.Longitude, 
 objLoc.Latitude, PolyWKT);

最後,此常式將重置地圖 (CreateNewMapObject)、從資料庫重新查詢位置清單 (InitMapPins) 並選擇新店鋪作為目前記錄 (SetLocation):

// Re-query and re-initialize map
 ObjectQuery<Location> locationQuery = db.Locations;
 ObjectQuery<vLocation> vlocationQuery = db.vLocations;
 locationList = locationQuery.ToList();
 vlocationList = vlocationQuery.ToList();
 objMap.Saved = true;
 CreateNewMapObject();
 InitMapSymb();
 InitMapPins();
 SetLocation( locationList.Count – 1 );
 e.cancel = true;
}

行 e.cancel=true;防止 MapPoint 進一步處理按一下事件。 後面是存儲過程 uspAddLocation(參見圖 11)。

圖 11 uspAddLocation 存儲過程

CREATE PROCEDURE [dbo].[uspAddLocation]
@Longitude FLOAT,
@Latitude FLOAT,
@PolyWKT NVARCHAR(MAX)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE @NewLocID int = 0
SELECT @NewLocID = MAX(LocID)+1 FROM Locations

DECLARE @NewPoly geography
SET @NewPoly = geography::STPolyFromText(@PolyWKT,4326)

INSERT INTO Locations(LocID,Name,Address,City,State,Format,Location,TradeArea)
VALUES(@NewLocID, 'New Location ' + CAST(@NewLocID As varchar(3)), '123 Main',   
 'Anywhere', 'ST', 'Food', geography::Point(@Latitude,@Longitude,4326), 
 @NewPoly)

SELECT @NewLocID AS NewLocID

END

您可以查看 INSERT 語句之前為多邊形創建的新 geography 實例和變數,其中 Point 位置通過 INSERT 方法內部的 Point 方法創建。 兩種方法均有效。

圖 12 中的事件處理代碼處理“上一個”和“下一個”按鈕、凸球面核取方塊和表單關閉,後者將完成應用程式。

图 12 完成应用程序

private void prev_Click(object sender, EventArgs e)
{
  IncDecLocation(-1);
}

private void next_Click(object sender, EventArgs e)
{
  IncDecLocation(1);
}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
  IncDecLocation();
}

private void Map_FormClosing(object sender, FormClosingEventArgs e)
{
  db.Dispose();
  MPctrl.ActiveMap.Saved = true;
}

查看和直觀編輯 SQL Server 地理空間資料

本文涵蓋甚廣,其中演示了 SQL Server 中完整的端到端應用程式,展示了如何使用 SQL Server Spatial 和 MapPoint 方法往返傳遞資料以顯示和編輯實際資訊。

此處演示的原則可以進一步深入。 請保留一份本地資料副本以確保快速更新地圖,但對於海量資料集而言,這並不現實。 在這些情況下,應該逐個記錄提取資料,最好使用緩存機制。

MapPoint 可以執行一些有用的地理空間操作(例如,駕車時間區域計算),但對於完整 GIS 所需的許多地理空間操作則無能為力。 本文中使用了兩個來自 SQL Server Spatial 擴展程式的此類操作:STConvexHull 和 STDistance。 空間擴展程式中提供的其他高級功能包括測量地理特徵的長度和寬度以及查找多邊形的並集和交集。 這些功能可用於創建複雜的地域管理應用程式。 這可以組合地域或查找存在店鋪同業競爭的重疊情況。

與此類似,也可以利用 MapPoint 的優勢。 MapPoint 能夠進行離線地理編碼。 本例中使用現有座標,但 MapPoint 地理編碼器也可用於定位街道位址。 MapPoint 中還提供了多種縣、郵遞區號和人口普查地域級別的人口統計資料庫。 這些資料可以繪製在店鋪地圖上,從而可以方便地進行比較,例如,店鋪銷售額與當地人口和收入水準的比較情況。

展望未來,SQL Server Spatial 有望在 SQL Server 的下一版本中實現跨越式提升,MapPoint 產品則通過在最近的兩個版本中實現新的開發和功能而得以復興,並且這種趨勢仍將持續下去。 此外,實體框架將繼續增加對新欄位類型的支援,包括空間資料類型,這將改進 SQL Server 與 MapPoint 之間的通信。 總而言之,這些技術構成了用於開發地圖應用程式的可靠、強大且不斷發展的平臺。

Eric Frost 是 Microsoft MVP 和業務應用程式開發人員,專注于 GIS/地圖應用程式。.他管理著活躍的 Microsoft 地圖技術論壇 mapforums.com,聯繫方式如下:eric.frost@mp2kmag.com

Richard Marsden 是 Microsoft MVP 和兼職軟體發展人員。他在 mapping-tools.com 上出售多種 MapPoint 擴展程式並運營了一個 GeoWeb Guru 網站,網址為:geowebguru.com

衷心感謝以下技術專家對本文的審閱: Bob Beauchemin , Ed Katibah Amar Nityananda