打造地圖拼接利器(三)圖源配置

打造地圖拼接利器(三)圖源配置

GMap.net內(nèi)置了74個地圖圖源,清單如下:

ArcGIS_DarbAE_Q2_2011_NAVTQ_Eng_V5_MapProvider ArcGIS_DarbAE_Q2_2011_NAVTQ_Eng_V5_Map;
  ArcGIS_Imagery_World_2D_MapProvider ArcGIS_Imagery_World_2D_Map;
  ArcGIS_ShadedRelief_World_2D_MapProvider ArcGIS_ShadedRelief_World_2D_Map;
  ArcGIS_StreetMap_World_2D_MapProvider ArcGIS_StreetMap_World_2D_Map;
  ArcGIS_Topo_US_2D_MapProvider ArcGIS_Topo_US_2D_Map;
  ArcGIS_World_Physical_MapProvider ArcGIS_World_Physical_Map;
  ArcGIS_World_Shaded_Relief_MapProvider ArcGIS_World_Shaded_Relief_Map;
  ArcGIS_World_Street_MapProvider ArcGIS_World_Street_Map;
  ArcGIS_World_Terrain_Base_MapProvider ArcGIS_World_Terrain_Base_Map;
  ArcGIS_World_Topo_MapProvider ArcGIS_World_Topo_Map;
  BingHybridMapProvider BingHybridMap;
  BingMapProvider BingMap;
  BingSatelliteMapProvider BingSatelliteMap;
  CloudMadeMapProvider CloudMadeMap;
  CzechGeographicMapProvider CzechGeographicMap;
  CzechHistoryMapProvider CzechHistoryMap;
  CzechHistoryMapProviderOld CzechHistoryOldMap;
  CzechHybridMapProvider CzechHybridMap;
  CzechHybridMapProviderOld CzechHybridOldMap;
  CzechMapProvider CzechMap;
  CzechMapProviderOld CzechOldMap;
  CzechSatelliteMapProvider CzechSatelliteMap;
  CzechSatelliteMapProviderOld CzechSatelliteOldMap;
  CzechTuristMapProvider CzechTuristMap;
  CzechTuristMapProviderOld CzechTuristOldMap;
  CzechTuristWinterMapProvider CzechTuristWinterMap;
  EmptyProvider EmptyProvider;
  GoogleChinaHybridMapProvider GoogleChinaHybridMap;
  GoogleChinaMapProvider GoogleChinaMap;
  GoogleChinaSatelliteMapProvider GoogleChinaSatelliteMap;
  GoogleChinaTerrainMapProvider GoogleChinaTerrainMap;
  GoogleHybridMapProvider GoogleHybridMap;
  GoogleKoreaHybridMapProvider GoogleKoreaHybridMap;
  GoogleKoreaMapProvider GoogleKoreaMap;
  GoogleKoreaSatelliteMapProvider GoogleKoreaSatelliteMap;
  GoogleMapProvider GoogleMap;
  GoogleSatelliteMapProvider GoogleSatelliteMap;
  GoogleTerrainMapProvider GoogleTerrainMap;
  LatviaMapProvider LatviaMap;
  Lithuania3dMapProvider Lithuania3dMap;
  LithuaniaHybridMapProvider LithuaniaHybridMap;
  LithuaniaHybridOldMapProvider LithuaniaHybridOldMap;
  LithuaniaMapProvider LithuaniaMap;
  LithuaniaOrtoFotoMapProvider LithuaniaOrtoFotoMap;
  LithuaniaOrtoFotoOldMapProvider LithuaniaOrtoFotoOldMap;
  LithuaniaReliefMapProvider LithuaniaReliefMap;
  LithuaniaTOP50 LithuaniaTOP50Map;
  MapBenderWMSProvider MapBenderWMSdemoMap;
  NearHybridMapProvider NearHybridMap;
  NearMapProvider NearMap;
  NearSatelliteMapProvider NearSatelliteMap;
  OpenCycleLandscapeMapProvider OpenCycleLandscapeMap;
  OpenCycleMapProvider OpenCycleMap;
  OpenCycleTransportMapProvider OpenCycleTransportMap;
  OpenSeaMapHybridProvider OpenSeaMapHybrid;
  OpenStreet4UMapProvider OpenStreet4UMap;
  OpenStreetMapProvider OpenStreetMap;
  OpenStreetMapQuestProvider OpenStreetMapQuest;
  OpenStreetMapQuestHybridProvider OpenStreetMapQuestHybrid;
  OpenStreetMapQuestSatteliteProvider OpenStreetMapQuestSattelite;
  OviHybridMapProvider OviHybridMap;
 OviMapProvider OviMap;
  OviSatelliteMapProvider OviSatelliteMap;
  OviTerrainMapProvider OviTerrainMap;
  SpainMapProvider SpainMap;
  SwedenMapProvider SwedenMap;
  TurkeyMapProvider TurkeyMap;
  WikiMapiaMapProvider WikiMapiaMap;
  YahooHybridMapProvider YahooHybridMap;
  YahooMapProvider YahooMap;
  YahooSatelliteMapProvider YahooSatelliteMap;
  YandexHybridMapProvider YandexHybridMap;
  YandexMapProvider YandexMap;
  YandexSatelliteMapProvider YandexSatelliteMap;

但在實際使用中,大部分都因一些未知因素而無法訪問,特別是國外的地圖,大部分對我國邊境標(biāo)繪錯誤,需謹(jǐn)慎使用。而且這些地圖中,鮮有國內(nèi)地圖商的地址。

為便于使用國內(nèi)地圖,我們需要寫一些訪問國內(nèi)地圖數(shù)據(jù)的代碼,還好,GMap.net開源,我們可以照貓畫虎,寫一個通用的TMSProvider。

在解決方案資源管理器中建一個文件夾,名為Utils。

要是用自定義Provider,首先建一個基類TmsProviderBase,讓他繼承自GMapProvider,并重寫2個方法。

using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.Projections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mapmeger
{
    public abstract class TmsProviderBase : GMapProvider
    {
        public TmsProviderBase()
        {
            MaxZoom = null;
            RefererUrl = "";
        }

        public override PureProjection Projection
        {
            get { return MercatorProjection.Instance; }
        }

        GMapProvider[] overlays;
        public override GMapProvider[] Overlays
        {
            get
            {
                if (overlays == null)
                {
                    overlays = new GMapProvider[] { this };
                }
                return overlays;
            }
        }
    }
}

然后新建一個類TmsProvider,繼承自我們剛新建的類TmsProviderBase,重新其核心方法

public override PureImage GetTileImage(GPoint pos, int zoom){}

當(dāng)我們使用自定義的地圖源時,就會調(diào)用這個函數(shù),傳來瓦片坐標(biāo)GPoint和層級,然后通過網(wǎng)絡(luò)請求,返回瓦片圖片對象。

GMap.net為我們提供了一個函數(shù)GetTileImageUsingHttp(string url),用以通過一個網(wǎng)絡(luò)瓦片地址返回一個瓦片圖片。

如何獲得這個地址呢,我們以獲取天地圖瓦片地址為例。打開谷歌瀏覽器,輸入https://www.tianditu.gov.cn/,按F12進(jìn)入瀏覽器調(diào)試模式,選擇Network選項卡,然后調(diào)整地圖大小,可以看到圖片請求地址:

3.1.png

拷貝其中一個,可以看到:

https://t3.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL=11&TILEROW=5&TILEMATRIX=4&tk=9a02b3cdd29cd346de4df04229797710

其中,t3代表第3個服務(wù)器,TILECOL=11&TILEROW=5&TILEMATRIX=4代表x=11,y=5,z=4,最后還有一個密鑰tk,如果沒有這個tk,就無法訪問到數(shù)據(jù)。密鑰可以通過注冊天地圖開發(fā)者賬號申請,但普通開發(fā)者每天只能訪問10000次數(shù)據(jù),公司和政府機(jī)構(gòu)會比較多,分別為300w和500w。

在實際使用過程中,內(nèi)置GetTileImageUsingHttp(string url)函數(shù)并不能獲取到所有網(wǎng)站的數(shù)據(jù),因為地圖服務(wù)端認(rèn)為客戶端不是瀏覽器,所以我們要重新一個請求程序,在http請求頭中加入“我是瀏覽器”的聲明,才可以獲取到數(shù)據(jù)。

我們新建一個Tools類,再新建一個下載圖片的函數(shù):

   public static byte[] downloadTile(string url)
        {
            try
            {
                WebClient myClient = new WebClient();
                myClient.Headers.Add( "User-Agent","Mozilla/5.0(Windows NT 6.1;Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0");
                myClient.Encoding = Encoding.UTF8;
                Uri uri = new Uri(url);
                byte[] bts = myClient.DownloadData(uri);
                return bts;
            }
            catch (Exception err)
            {
                return null;
            }
        }

同時,為了提高程序復(fù)用性,我們通過一個地址就可以自動生成一個心得Provider,需要寫一個地址解析函數(shù),自動替換{x},{y},{z}和服務(wù)器地址,比如把https://a[1-4].tile.openstreetmap.org/{z}/{x}/{y}.png根據(jù)請求自動替換為https://a1.tile.openstreetmap.org/3/1/1.png


還有一個很重要的問題,就是圖片合并的問題,有些衛(wèi)星圖是不帶路網(wǎng)和地名的,需要將兩個圖形合并后返回。所以我們?yōu)門msProvider提供一個參數(shù),用以將1種圖或2種圖合并后返回給地圖程序。

  public static string getUrl(string urlformat,int x,int y ,int z)
        {
            int leftSignPos = -1, rightSignPos = -1;
            leftSignPos = urlformat.IndexOf('[');
            rightSignPos = urlformat.IndexOf(']');
            if (leftSignPos > 0 && rightSignPos > leftSignPos)
            {
                string serverstr = urlformat.Substring(leftSignPos + 1, rightSignPos - leftSignPos - 1);
                int startnum = int.Parse(serverstr.Split('-')[0]);
                int endnum = int.Parse(serverstr.Split('-')[1]);
                long num = (x + y) % (endnum - startnum) + startnum;
                string nurl = urlformat.Substring(0, leftSignPos) + num + urlformat.Substring(rightSignPos + 1);
                urlformat = nurl;
            }
            urlformat = urlformat.Replace("{x}", x.ToString())
                .Replace("{y}", y.ToString())
                .Replace("{z}", z.ToString());
            return urlformat;
        }

圖片返回函數(shù)如下:

 PureImage GetImgFromUrl(GPoint pos, int zoom, string url)
        {
            //return GetTileImageUsingHttp(MakeTileImageUrl(pos, zoom, url));
            string durl = MakeTileImageUrl(pos, zoom, url);
            byte[] bts = Tools.downloadTile(durl);
            MemoryStream ms = new MemoryStream();
            ms.Write(bts, 0, bts.Length);
            Image img = Bitmap.FromStream(ms);
            GMapImage gimg = new GMapImage();
            gimg.Data = ms;
            gimg.Img = img;
            ms.Dispose();
            return gimg;
        }

        PureImage GetMultiImgFromUrl(GPoint pos, int zoom, string url1, string url2)
        {
            GMapImage img = new GMapImage();
            string durl1 = MakeTileImageUrl(pos, zoom, url1);
            byte[] bts1 = Tools.downloadTile(durl1);
            string durl2 = MakeTileImageUrl(pos, zoom, url2);
            byte[] bts2 = Tools.downloadTile(durl2);

            MemoryStream ms1 = new MemoryStream();
            ms1.Write(bts1, 0, bts1.Length);
            Image img1 = Bitmap.FromStream(ms1);
            
            MemoryStream ms2 = new MemoryStream();
            ms2.Write(bts2, 0, bts2.Length);
            Image img2 = Bitmap.FromStream(ms2);

            Image bit = new Bitmap(256,256);
            Graphics g = Graphics.FromImage(bit);

            g.DrawImage(img1, 0, 0, img1.Width, img1.Height);
            g.DrawImage(img2, 0, 0, img2.Width, img2.Height);
            MemoryStream ms = new MemoryStream();
            bit.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            img.Img = bit;
            img.Data = ms;
            g.Dispose();
            ms.Close();
            ms1.Dispose();
            ms2.Dispose();
            return img;
        }

在前端,我們通過一個配置文件config.txt,將能使用的圖源地址進(jìn)行配置:

//配置說明:豎線前為地圖名稱,后為TMS地址,方括號內(nèi)為服務(wù)器序號,{x}\{y}\{z}分別代表瓦片坐標(biāo)。很多地圖都需要key授權(quán),天地圖的key可以自行申請,每天都會受到使用次數(shù)限制
openstreet交通|https://a.tile.openstreetmap.org/{z}/{x}/{y}.png
高德影像|https://webst0[1-4].is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}
高德矢量|http://wprd0[1-4].is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}
高德注記|https://wprd0[1-4].is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=8
天地圖交通|https://t[1-4].tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=c03258c0232becff8dfbd108c02a3265
天地圖衛(wèi)星|https://t[1-4].tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=c03258c0232becff8dfbd108c02a3265
天地圖地形|https://t[1-4].tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=c03258c0232becff8dfbd108c02a3265
天地圖注記|https://t[1-4].tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=c03258c0232becff8dfbd108c02a3265

在主程序加載時,將圖層分別綁定到地圖和覆蓋圖上。

 private void InitMapurls()
        {
            string configfile = Application.StartupPath + "\\config.txt";
            if (File.Exists(configfile))
            {
                string[] configlines = File.ReadAllLines(configfile);
                for (int i = 0; i < configlines.Length; i++)
                {
                    if (!configlines[i].StartsWith("http://"))
                    {
                        curmapurls.Add(configlines[i].Split('|')[1]);
                        break;
                    }
                }
                DataTable dt = new DataTable();
                dt.Columns.Add("text");
                dt.Columns.Add("value");
                DataTable dt1 = dt.Clone();
                for (int i = 0; i < configlines.Length; i++)
                {
                    if (!configlines[i].StartsWith("http://"))
                    {
                        mapurls.Add(configlines[i]);
                        DataRow row = dt.NewRow();
                        row[0] = configlines[i].Split('|')[0];
                        row[1] = configlines[i].Split('|')[1];
                        dt.Rows.Add(row);
                        dt1.Rows.Add(row.ItemArray);
                    }
                }
                CBLayer1.DataSource = dt;
                CBLayer1.DisplayMember = "text";
                CBLayer1.ValueMember = "value";
                CBLayer2.DataSource = dt1;
                CBLayer2.DisplayMember = "text";
                CBLayer2.ValueMember = "value";
            }
            else
            {
                curmapurls.Add("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png");
            }

        }

當(dāng)圖源下拉框變化時,切換地圖:

    void changeMap()
        {
            if (isfirtload)
                return;
            curmapurls.Clear();
            curmapurls.Add(((DataRowView)CBLayer1.SelectedItem)[1].ToString());
            if (CBShow.CheckState==CheckState.Checked)
            {
                curmapurls.Add(((DataRowView)CBLayer2.SelectedItem)[1].ToString());
            }
            gmapc.MapProvider = new TmsProvider(curmapurls);
        }

同時,將gmapc.MapProvider =new TmsProvider(curmapurls);設(shè)置為自定義圖源。其中curmapurls為一個泛型,用來記錄右上角選擇的地圖的地址。

3.2.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容