各種外掛範例


在開始以前,需要先建立基本專案。

步驟 1. 目標是使用 MicroSoft Visual Studio 2019(或以上之版本)建立一個名為 MyClass.dll 的函式庫。首先新增類別庫專案,在此請使用[.Net Framework 4.7.2],接著為專案命名,在本範例命名為 MyClass。

PluginSample

步驟 2. 請在右邊[方案總管]中找到[參考],點擊滑鼠右鍵後點選[加入參考…],視窗開啟後,選擇[瀏覽]頁籤,至安裝目錄下找到TMPEngine.dll檔案並按下[確定],即可將 TMPEngine.dll 加入參考。

PluginSample

步驟 3. 加入參考後請於`Class1.cs上方加入以下程式碼:

using PilotGaea.Geometry;
using PilotGaea.TMPEngine;
using PilotGaea.Serialize;

以上為所有外掛的前置作業,完成後下面將示範各個外掛的實作過程。

DoCommand

[info] 小提示:
範例程式碼:Github

這邊會實作兩個 Docommand 功能 ─ GetAllLayerInfo 與 GetLayerInfo,這兩個功能已存在於預設外掛DefaultPlugin.dll

步驟 1. 專案建置後,請在Class1後方加入繼承DoCmdBaseClass

public class Class1 : DoCmdBaseClass

步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,接著請點擊燈泡圖案,接著點選[實作抽象類別]

DoCommand

點選後系統會自動產生預設的繼承函式,自動生成的程式碼約如下所示:

public class Class1 : DoCmdBaseClass
{
    public override void DeInit() 
    {
        throw new NotImplementedException();
    }
    public override bool DoCmd(CGeoDatabase DB, string Cmd, string SessionID, VarStruct InputParm, out VarStruct RetParm) 
    {
        throw new NotImplementedException();
    }
    public override string[] GetSupportCmds() 
    {
        throw new NotImplementedException();
    }
    public override bool Init() 
    {
        throw new NotImplementedException();
    }
}

步驟 3. 請宣告一個List的全域變數,用來儲存要新增的指令。

private List<string> m_Cmds;

步驟 4. 實作Init函式:找到系統已產生覆寫(Override)繼承自DoCmdBaseClassInit函式,此函式為初始化函式庫,我們將在此函式中新增所有此函式庫支援之 DoCommand 指令名稱,可依需求自行新增。

public override bool Init()
{
    m_Cmds = new List<string>();
    m_Cmds.Add("GetAllLayerInfo");
    m_Cmds.Add("GetLayerInfo");
    return true;
}

步驟 5. DeInit函式為覆寫(Override)繼承自DoCmdBaseClass之函式DeInit(),此函式將在外掛重新載入或主程式結束時被呼叫,預設為不執行任何指令。

public override void DeInit() {
// 預設為不執行任何指令
}

步驟 6. 實作 Docmd 函式:請找到系統已產生覆寫(Override)繼承自DoCmdBaseClass的 Docmd 函式,此函式為呼叫功能之主要進入點,在此我們將判斷傳進來的指令字串,並呼叫相對應的函式執行我們寫好的功能。如果此函式回傳為false,client 將會收到http status code 500(伺服器內部錯誤)。

public override bool DoCmd(CGeoDatabase DB, string Cmd, string SessionID, VarStruct InputParm, out VarStruct RetParm)
{
    bool Ret = false;
    RetParm = null;
    switch (Cmd)
    {  // 在此的指令需對應上方初始化時建立的指令
        case "GetAllLayerInfo":
            Ret = GetAllLayerInfo(DB, SessionID, out RetParm);
            break;
        case "GetLayerInfo":
            Ret = GetLayerInfo(DB, SessionID, InputParm, out RetParm);
            break;
    }
    return Ret;
}

[warning] 注意事項: 此時會因為尚未實作函式而顯示錯誤,請先忽略。

步驟 7. 實作GetSupportCmds函式:找到系統已產生覆寫(Override)繼承自DoCmdBaseClassGetSupportCmds函式,此函式功能為讓外部取得此函式庫中所有支援之指令字串。

public override string[] GetSupportCmds()
{
    return m_Cmds.ToArray();
}

步驟 8. 在此將實作一個自定義的函式,此函式會以遞迴的方式讀取圖層,在此函式中,我們先判斷此圖層是否為一個群組,若是群組,則進一步取出群組中的子圖層;若不是群組,則直接取得圖層資訊放入Result參數物件中,以此方式遞迴。

[warning] 注意事項: 此函式為自定義函式,在此僅是範例,可自行研究並加入或修改更豐富之功能。

private void RecursiveLayerInfo(CLayer Layer, VarStruct Result)
{
    Result["islayerset"].Set(Layer.Type == LAYER_TYPE.SET);
    Result["layername"].Set(Layer.Name);
    Result["setting"].Set(Layer.GetSetting());
    if (Layer.Type == LAYER_TYPE.SET)
    {
        int count = ((CLayerSet)Layer).Layers.Count;
        if (count > 0)
        {
            Result["layers"].CreateArray(count);
            for (int i = 0; i < count; i++)
            {
                VarStruct _Result = (Result["layers"].GetArray())[i].CreateStruct();
                RecursiveLayerInfo(((CLayerSet)Layer).Layers[i], _Result);
            }
        }
    } else {
        Result["epsgcode"].Set(Layer.EPSG);
        Result["type"].Set(Convert.ToInt32(Layer.Type));
        Result["boundary"].Set(Layer.Boundary);
    }
}

步驟 9. 將上述函式完成後,就可以實作GetLayerInfoGetAllLayerInfo函式了。首先是GetLayerInfo,此函式功能為取得指定名稱之 2D 圖層;此函式會先從傳進的參數InputParm取得參數內容,接著判斷 DB 中的根群組中是否含有此圖層,若圖層存在則使用已建立之RecursiveLayerInfo函式取得圖層資訊。

[warning] 注意事項: 此函式為自定義函式,在此僅是範例,可自行研究並加入或修改更豐富之功能。

private bool GetLayerInfo(CGeoDatabase DB, string SessionID, VarStruct InputParm, out VarStruct RetParm) 
{
    bool Ret = true;
    RetParm = new VarStruct();
    CGroup Group = DB.GetGroup();
    string LayerName = InputParm["layername"].GetString();
    CLayer Layer = null;
    if (Group.IsLayerOK(LayerName))
    {
        Layer = DB.FindLayer(LayerName);
    }
    if (Layer == null)
    {
        DB.FindSessionLayer(LayerName);
    }
    if (Layer != null)
    {
        RetParm["success"].Set(true);
        VarStruct Result = new VarStruct();
        RecursiveLayerInfo(Layer, Result);
        RetParm["ret"].Set(Result);
    } else {
        RetParm["success"].Set(false);
    }
    return Ret;
}

步驟 10. 接著是實作GetAllLayerInfo函式,此函式功能為取得 MapServer 上所有已發布之 2D 圖層資訊;此函式會先建立要回傳的RetParm參數物件,此物件中將會存放所有回傳內容。由於能用的圖層都來自於 MapServer 的 DataBase (DB) ,因此須從 DB 取得根群組,再取得群組中的所有圖層,就可以得到所有 2D 圖層的數量,最後就可以使用以此數量為上限的迴圈執行已建立之RecursiveLayerInfo函式來取得所有圖層資訊並回傳。

[warning] 注意事項: 此函式為自定義函式,在此僅是範例,可自行研究並加入或修改更豐富之功能。

private bool GetAllLayerInfo(CGeoDatabase DB, string SessionID, out VarStruct RetParm)
{
    bool Ret = true;
    RetParm = new VarStruct();
    RetParm["success"].Set(true);
    CGroup Group = DB.GetGroup();
    int Count = Group.Layers.Count;
    VarArray result = RetParm["ret"].CreateArray(Count);
    for (int i = 0; i < Count; i++)
    {
        VarStruct _result = result[i].CreateStruct();
        RecursiveLayerInfo(Group.Layers[i], _result);
    }
    return Ret;
}

步驟 11. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug(或是\bin\Release,依建置類型決定)目錄內將檔案複製到安裝目錄下的plugins目錄中,最後用 client 進行呼叫查看執行結果。

DoCommand 非同步版本

[info] 小提示:
範例程式碼:Github

DoCommand也有提供非同步版本的實作。當你需要 server 同時執行多項DoCommand作業,或者你想讓這項作業可以由前端詢問進度或是中斷,你可以使用非同步的DoCommand
在這裡會示範加入一個簡單的非同步DoCommand範例。

步驟 1. 這裡的程式碼接續之前DoCommand章節的內容。同樣先在Init()裡加入新的指令名稱。我們叫它"ConnectionTest"。希望它在呼叫之後回傳一筆簡單的資料,讓我們知道DoCommand當前是成功運行的。

public override bool Init()
{
    m_Cmds = new List<string>();
    m_Cmds.Add("GetAllLayerInfo");
    m_Cmds.Add("GetLayerInfo");
    m_Cmds.Add("ConnectionTest");
    return true;
}

接著需要複寫DoCmdAsync這個函式。此函式是以virtual關鍵字宣告的,不強迫實作,所以 Visual Studio 不會幫你加入,請自己加。之後比照之前DoCommand的方式加入判斷式跟函式。

public override bool DoCmdAsync(CGeoDatabase DB, string Cmd, string SessionID, VarStruct InputParam, int CommandID, CommandStatus Status) 
{
    bool Ret = false;
    switch (Cmd) 
    {
        case "ConnectionTest":
            Ret = ConnectionTest(DB, SessionID, InputParam,Status);
            break;
    }
    return Ret;
}

接下來我們實作ConnectionTest這個函式。

private bool ConnectionTest(CGeoDatabase dB, string sessionID, VarStruct inputParam, CommandStatus status)
{
    status.m_Data["success"].Set(false);
    for (int i = 0; i <= 100; i++)
    {
        status.SetProgress(i);
        if (status.isAbort())
        {
            string msg_aborted = "Connection test was aborted.";
            status.m_Data["message"].Set(msg_aborted);
            return true;
        }
    }
    string msg_succeeded = "Connection test succeeded.";
    status.m_Data["message"].Set(msg_succeeded);
    status.m_Data["success"].Set(true);
    return true;
}

這樣就完成了。
這裡可以發現到,你需要自己在 server 端設定進度和建立中斷作業的機制。

步驟 2. 客戶端發送非同步的DoCommand請求方式與發送同步DoCommand方式相同,差別在於取得資料時會透過函式回傳的手柄來操作。除了取得資料,還有中斷、詢問進度等功能都需要透過手柄。

這邊示範一下JavaScript端的寫法。
首先我們先宣告伺服器的連線資訊。

let ServerUrl = "127.0.0.1";
let ServerPort = 8080;
let ProxyUrl = "http://" + ServerUrl + ":" + ServerPort;

為了方便,我們寫一個可以幫我們快速加入按鈕的函式AddButton()

// 加入按鈕
function AddButton(text, event, id = "") {
  const button = document.createElement("button");
  button.innerText = text;
  button.onclick = event;
  if (id != "") {
    button.id = id;
  }
  document.body.appendChild(button);
}

再來我們需要可以在送出非同步DoCommand之後,每隔一秒鐘向 server 詢問一次進度的函式GetProgress()

function GetProgress(handle) {
  function work() {
    let ret = handle.getProgress();
    console.log(ret);
    return ret;
  }
  let itvId = setInterval(() => {
    let ret = work();
    if (parseInt(ret.Progress) >= 100) {
      // 進度 >= 100時停止詢問
      clearInterval(itvId);
    }
  }, 1000); // 每一秒問一次
  return itvId; // 回傳 setInterval 的 Id,讓 setInterval 能從外面被中斷
}

再來我們建立一個Main(),將主要的行為囊括在內。

function Main() {
  let handle = null;
  let itvId = null;
  AddButton("doByHandle", () => {
    // 以手柄方式呼叫 docmd
    let param = {};
    handle = ov.DoCommand.doByHandle(proxyUrl, "ConnectionTest", param);
    // 呼叫完成後開始向 server 問進度
    itvId = getProgress(handle);
  });
  AddButton("getResult", () => {
    // 取得手柄 docmd 資料
    if (handle === null) return;
    let ret = handle.getResult();
    console.log(ret);
    if (parseInt(ret.Progress) >= 100) {
      handle = null;
    }
  });
  AddButton("abort", () => {
    // 中斷手柄 docmd 作業
    if (itvId === null || handle === null) return;

    let ret = handle.abort();
    console.log(ret);
    if (ret.success) {
      clearInterval(itvId);
      console.log("aborted.");
    } else {
      console.log("not aborted.");
    }
  });
}

可以看到,當呼叫ov.DoCommand.doByHandle()之後,它會回傳一個手柄(handle)。若需要進行中斷作業,詢問進度或是取得資料的行為,都會透過這個手柄來操作。

最後呼叫一次Main()

Main();

這樣 Client 端也完成了。

Account

[info] 小提示:
範例程式碼:Github

這邊會實作具有登入的功能。
每個圖層設定都有個AccessControl,當這個值被設定為true時,此圖層就必須登入才能夠存取。

步驟 1. 首先請在Class後方加入繼承AccountBaseClass

public class AccessControlClass : AccountBaseClass

步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,請點擊燈泡圖案,接著點選[實作抽象類別]

Account

點選後系統會自動產生預設的繼承函式,自動生成的程式碼應如下所示:

public class AccessControlClass : AccountBaseClass 
{
    public override void DeInit() 
    {
        throw new NotImplementedException();
    }
    public override bool Init() 
    {
        throw new NotImplementedException();
    }
    public override bool Login(LoginInputParameter InputData, out LoginOutputParameter OutputData) 
    {
        throw new NotImplementedException();
    }
}

步驟 3. 實作Init函式–找到系統已產生覆寫(Override)繼承自AccountBaseClassInit函式,此函式為初始化函式庫,預設為不執行任何指令,開發人員可以在此加入初始化時要做的指令。

public override bool Init() 
{
    return true;
}

步驟 4. DeInit函式為覆寫(Override)繼承自AccountBaseClass之函式DeInit(),此函式將在AccessCntrol函式庫結束時被呼叫,預設為不執行任何指令。

public override void DeInit() {
    // 預設為不執行任何指令
}

步驟 5. 實作Login函式–找到系統已產生覆寫(Override)繼承自AccountBaseClassLogin函式,此函式為呼叫功能之主要進入點。
在此我們將判斷傳進來的 InputData,接著做出我們想要的判斷,最後再由OutputData.CanLogin來決定是否要讓此請求存取圖層,並將所屬群組名稱一同傳回,此範例為簡單的帳號密碼判斷。
由於網頁 Client 端無法使用參數輸入帳號密碼,所以可以在 Login 函式中新增一個判斷 IP 的條件式,讓使用網頁 Client 端的使用者可以使用白名單登入。

public override bool Login(LoginInputParameter InputData, out LoginOutputParameter OutputData) 
{
    bool Ret = false;
    OutputData = new LoginOutputParameter();
    if ((InputData.Username.ToLower() == "pilotgaea" && InputData.Password == "aeagtolip") || InputData.IP == "192.168.17.1")
    {
        bool Admin = false;
        for (int i = 0; i < InputData.Groups.Count; i++)
        {
            if (InputData.Groups[i].Name == "Administrators")
            {
                 Admin = true;
                 break;
            }
        }
        OutputData.CanLogin = true;
        if (Admin) OutputData.GroupName = "Administrators";
        else OutputData.GroupName = "Everyone";
        OutputData.Memo = "";
    }
    Ret = true;
    return Ret;
}

[info] 補充說明: 其他詳細參數如下列介紹:

  • InputData:
    • Groups:請求者所在的群組列表。
    • IP:請求者的 IP。
    • LayerName:請求圖層的圖層名稱。
    • Password:請求者輸入的密碼。
    • ServiceType:請求圖層的類型(wmts、wms……)。
    • SessionID:請求者的 SessionID。
    • UserName:請求者輸入的使用者名稱。
  • OutputData:
    • CanLogin:是否同意登入存取圖層。
    • GroupName:可以回傳請求者所在的群組。
    • Memo:備忘錄。

步驟 6. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug目錄內將檔案複製到安裝目錄下的plugins目錄中,接著請開啟 MapServer 勾選圖層的AccessControl功能,將伺服器儲存後並重新啟動。

Account_MapServer

步驟 7. 在此以第二章與第六章所完成的網頁與視窗程式作為範例,可以發現兩者皆已經無法顯示圖層。

步驟 8. 請打開視窗程式專案,並到程式碼分頁中,請在Form1_Shown事件中找到此行程式碼:

int id = m_MapDocument.NewTileMapLayer(m_sLayer, urlPatterns, mtxSet);

請將此行重新輸入,可看見此函式可輸入參數作為帳號密碼:

Account_APP

接著將程式碼增加輸入用參數,並重新建置啟動程式:

int id = m_MapDocument.NewTileMapLayer(m_sLayer, urlPatterns, mtxSet,-1,"pilotgaea","aeagtolip");

執行後便可看到可以再次讀取出圖層。

FeatureInfo

[info] 小提示:
範例程式碼:Github

這邊會實作 WMTS 下查詢向量圖層資訊的功能(GetFeatureInfo)。

步驟 1. 首先請在Class後方加入繼承FeatureInfoBaseClass

public class FeatureInfoClass : FeatureInfoBaseClass

步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,請點擊燈泡圖案,接著點選[實作抽象類別]

FeatureInfo.PNG

點選後系統會自動產生預設的繼承函式,自動生成的程式碼應如下所示:

public class FeatureInfoClass : FeatureInfoBaseClass
{
    public override void DeInit()
    {
        throw new NotImplementedException();
    }
    public override bool GetFeatureInfo(CGeoDatabase DB, string SessionID, string LayerName, int EPSG, GeoPoint Point, double Distance, out VarStruct Ret)
    {
        throw new NotImplementedException();
    }
    public override bool Init()
    {
        throw new NotImplementedException();
    }
}

步驟 3. 實作Init函式–找到系統已產生覆寫(Override)繼承自FeatureInfoBaseClassInit函式,此函式為初始化函式庫,預設為不執行任何指令,開發人員可以在此加入初始化時要做的指令。

public override bool Init()
{
    return true;
}

步驟 4. DeInit函式為覆寫(Override)繼承自FeatureInfoBaseClass之函式DeInit(),此函式將在FeatureInfoBaseClass函式庫結束時被呼叫,預設為不執行任何指令。

public override void DeInit() {
    // 預設為不執行任何指令。
}

步驟 5. 實作GetFeatureInfo函式–找到系統已產生覆寫(Override)繼承自FeatureInfoBaseClassGetFeatureInfo函式,此函式為呼叫功能之主要進入點。
在此我們將判斷傳進來的LayerName,查詢目標範圍內的圖素,最後再根據圖素類型傳回,其中Distance為每個Pixel代表的公尺乘上 5。

public override bool GetFeatureInfo(CGeoDatabase DB, stringSessionID, string LayerName, int EPSG, GeoPoint Point, doubleDistance, out VarStruct Ans)
{
    bool Ret = false;
    Ans = new VarStruct();
    CVectorLayer Layer = DB.FindLayer(LayerName) as CVectorLayer_Base;
    if (Layer == null) return Ret;
    CEntityFetcher Fetcher = Layer.SearchByDistance(EPSG, Point, Distance);
    VarArray Arr = Ans["features"].CreateArray(Fetcher.Count);
    for (int i = 0; i < Fetcher.Count; i++)
    {
        GeoPoint p = new GeoPoint();
        GeoPolyline pl = new GeoPolyline();
        GeoPolygonSet pgs = new GeoPolygonSet();
        VarStruct feature = Arr[i].CreateStruct();
        switch (Fetcher.GetType(i))
        {
            case GEO_TYPE.POINT : {
                    Fetcher.GetGeo(i, ref p);
                    feature["geometry"].Set(p);
                }
                break;
            case GEO_TYPE.POLYLINE : {
                    Fetcher.GetGeo(i, ref pl);
                    feature["geometry"].Set(pl);
                }
                break;
            case GEO_TYPE.POLYGONSET : {
                    Fetcher.GetGeo(i, ref pgs);
                    feature["geometry"].Set(pgs);
                }
                break;
        }
    }
    Ret = true;
    return Ret;
}

步驟 6. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug目錄內將檔案複製到安裝目錄下的plugins目錄中,接著請啟動 MapServer。

步驟 7. 確認 MapServer 中有加入向量圖層,並將其命名為範例向量圖層,開起瀏覽器並在網址列輸入:

http://127.0.0.1:8080/wmts?Layer=範例向量圖層&Request=GetFeatureInfo&TileMatrixSet=EPSG:3857&i=127&j=127&TileRow=877&TileCol=1713&TileMatrix=11&InfoFormat=application/json

[info] 補充說明:
其他詳細參數如下列介紹:

  • Layer:要讀取資訊的圖層名稱。
  • TileMatrixSet:圖層右鍵編輯 → 進階設定就能看到。
  • i、j:在圖磚中的坐標。
  • TileRow、TileCol:圖磚縱、橫軸索引。
  • TileMatrix:圖磚資料層集合。
  • InfoFormat:回傳的結構。

上述所要代入的參數會根據向量圖的位置有所不同,但不管在哪個位置,GetFeatureInfo都會被呼叫,範例結果如下:

FeatureInfo_request.PNG

Snap

[info] 小提示:
範例程式碼:Github

這邊會實作鎖點提示功能,外掛部分只會提供圖素讓 Server 計算決定結果。

步驟 1. 首先請在Class後方加入繼承SnapBaseClass

public class SnapClass : SnapBaseClass

步驟 2. 此時由於尚未實作繼承的函式,所以會顯示有錯誤,這時請將滑鼠移動至紅色底線的地方,會出現燈泡提示,請點擊燈泡圖案,接著點選[實作抽象類別]

Snap.PNG

點選後系統會自動產生預設的繼承函式,自動生成的程式碼應如下所示:

public class SnapClass : SnapBaseClass
{
    public override void DeInit()
    {
        throw new NotImplementedException();
    }
    public override bool GetSnapGeometry(CGeoDatabase DB, string LayerName, GeoPoint Point, double Distance, int EPSGCode, out List<Geo> Geos)
    {
        throw new NotImplementedException();
    }
    public override bool Init()
    {
        throw new NotImplementedException();
    }
}

步驟 3. 實作Init函式–找到系統已產生覆寫(Override)繼承自SnapBaseClassInit函式,此函式為初始化函式庫,預設為不執行任何指令,開發人員可以在此加入初始化時要做的指令。

public override bool Init()
{
    return true;
}

步驟 4. DeInit函式為覆寫(Override)繼承自SnapBaseClass之函式DeInit(),此函式將在SnapBaseClass函式庫結束時被呼叫,預設為不執行任何指令。

public override void DeInit() {
    // 預設為不執行任何指令
}

步驟 5. 實作GetSnapGeometry函式–找到系統已產生覆寫(Override)繼承自SnapBaseClassGetSnapGeometry函式,此函式為呼叫功能之主要進入點,在此我們將判斷傳進來的LayerName,查詢目標範圍內圖素的所有點,將這群點作為鎖點計算的一部分來源。

public override bool GetSnapGeometry(CGeoDatabase DB, string LayerName, GeoPoint Point, double Distance, int EPSGCode, out List<Geo> Geos)
{
    bool Ret = false;
    Geos = new List<Geo>();
    CVectorLayer Layer = DB.FindLayer(LayerName) as CVectorLayer_Base;
    if (Layer == null) return Ret;
    CEntityFetcher Fetcher = Layer.SearchByDistance(EPSGCode, Point, Distance);
    for (int i = 0; i < Fetcher.Count; i++)
    {
        GeoPoint p = new GeoPoint();
        GeoPolyline pl = new GeoPolyline();
        GeoPolygonSet pgs = new GeoPolygonSet();
        switch (Fetcher.GetType(i))
        {
            case GEO_TYPE.POINT:
                Fetcher.GetGeo(i, ref p);
                Geos.Add(p);
                break;
            case GEO_TYPE.POLYLINE:
                Fetcher.GetGeo(i, ref pl);
                Geos.Add(pl);
                break;
            case GEO_TYPE.POLYGONSET:
                Fetcher.GetGeo(i, ref pgs);
                Geos.Add(pgs);
                break;
        }
    }
    // Ret = true; 
    // 如果傳回true,表示只拿這些圖素做計算
    return Ret;
}

步驟 6. 以上步驟皆完成後,請按下建置專案,由於類別庫無法直接執行,完成後請到專案資料夾中的\bin\Debug目錄內將檔案複製到安裝目錄下的plugins目錄中,接著請啟動 MapServer。

步驟 7. 延續第二章的網頁程式新增一個新的按鈕

<div id="MyControl" style="position: absolute;z-index: 1;">
  <button id="measure-length">MeasureLength</button>
  <button id="measure-area">MeasureArea</button>
  <button id="clear">Clear</button>
  <button id="change-color-by-distance">ChangeColorByDistance</button>
  <button id="snap">Snap</button>  // 新增
</div>

步驟 8. 確認 MapServer 中有加入向量圖層,將其命名為範例向量圖層,並在 Web 中載入

var layerName = "範例向量圖層";
var host = "http://127.0.0.1:8080/wmts?"; // 以本機MapServer為例。
var wmtsUrl =
  host +
  "Layer=" +
  layerName +
  "&style=default&TileMatrixSet=EPSG:3857Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix={TileZ}&TileCol{TileC}&TileRow={TileR}";
var Patterns = [wmtsUrl];
var im = mapDoc.NewTileMapLayerByMatrixSet("Vector", Patterns, m, -1);

步驟 9. 綁定點擊事件到剛剛新增的按鈕上,使其觸發鎖點功能

document.querySelector("#snap ").onclick = function () {
  var layerNam = "Vector";
  var pixel = 100;
  var type = "node";
  var radius = 10;
  var fillColor = "rgba(255, 0, 0, 1)";
  var strokeColor = "rgba(0, 255, 0, 1)";
  mapView.SetSnapPointSetting(
    layerNam,
    pixel,
    type,
    radius,
    fillColor,
    strokeColor
  );
};

點擊按鈕啟動,再點擊量測鈕,當靠近到指定範圍時,便會看到鎖點效果。

Copyright © PilotGaea 2022 Version:13.0 all right reserved,powered by Gitbook修訂時間: 2024-01-31 10:01:42