public static void saveMaps(Extent extent, double resolution) { //Get the online layers var layers = GetLayersForMap(App.CurrentProjectId); //Create an array for adding the layers into in an ordered fashion var mapLayersTemp = new MapLayer[layers.Count]; //Add online wms layers var layerStack = layers.OrderBy(o => o.order).ToList(); foreach (var layer in layerStack) { string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), ""); var files = Directory.GetFiles(filePath); FileStream destination = File.Create(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/new.mbtiles")); using (var sourceStream = File.Open(filePath, FileMode.Open, FileAccess.Read)) { sourceStream.CopyTo(destination); } //Now add the layers in their correct order var layerNo = Math.Max(layers.Count - layer.order, 0); var tileSource = WMSLayer.CreateTileSource(layer.url, layer.wmsLayer, "EPSG:3857"); var tileInfos = tileSource.Schema.GetTileInfos(extent, resolution); // 3) Fetch the tiles from the service Console.WriteLine("Show tile info"); foreach (var tileInfo in tileInfos) { var tile = tileSource.GetTile(tileInfo); Console.WriteLine( $"Layer: {layer.title}, " + $"tile col: {tileInfo.Index.Col}, " + $"tile row: {tileInfo.Index.Row}, " + $"tile level: {tileInfo.Index.Level} , " + $"tile size {tile.Length}"); } } }
/// <summary> /// Save each of the map layers on-screen (the extent is provided by the screen edges) to an mbtiles file /// </summary> /// <param name="extent"></param> public static async void saveMaps(Extent extent) { var basemap = Preferences.Get("BaseLayer", "swisstopo_pixelkarte"); //Check which basemap var cancel = false; MessagingCenter.Subscribe <Application>(App.Current, "CancelMapSave", (sender) => { //Listen for tile save updates and update the count cancel = true; }); //Get the online layers var layers = GetLayersForMap(App.CurrentProjectId); //Create an array for adding the layers into in an ordered fashion var mapLayersTemp = new MapLayer[layers.Count]; //Add online wms layers var layerStack = layers.OrderBy(o => o.order).ToList(); //Calculate number of tiles var noOfLayers = 0; //Calculate number of tiles long noOfTiles = 0; foreach (var layer in layerStack) { if (layer.visible) { var tileSource = WMSLayer.CreateTileSource(layer.url, layer.wmsLayer, "EPSG:3857"); foreach (var zoomScale in tileSource.Schema.Resolutions) { var tileInfos = tileSource.Schema.GetTileInfos(extent, zoomScale.Value.UnitsPerPixel); noOfTiles = noOfTiles + tileInfos.Count(); } noOfLayers++; } } if (basemap == "swisstopo_pixelkarte") { string swisstopoDbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/swisstopo.mbtiles"); TileLayer swisstopo = WMSLayer.CreatePixelkarteWMTSTileLayer(); foreach (var zoomScale in swisstopo.TileSource.Schema.Resolutions) { var stTileInfos = swisstopo.TileSource.Schema.GetTileInfos(extent, zoomScale.Value.UnitsPerPixel); noOfTiles = noOfTiles + stTileInfos.Count(); } } else if (basemap == "swissimage") { string swisstopoDbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/swissimage.mbtiles"); TileLayer swisstopo = WMSLayer.CreateSwissimageWMTSTileLayer(); foreach (var zoomScale in swisstopo.TileSource.Schema.Resolutions) { var stTileInfos = swisstopo.TileSource.Schema.GetTileInfos(extent, zoomScale.Value.UnitsPerPixel); noOfTiles = noOfTiles + stTileInfos.Count(); } } else { string osmDbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/osm.mbtiles"); TileLayer osm = OpenStreetMap.CreateTileLayer(); foreach (var zoomScale in osm.TileSource.Schema.Resolutions) { var osmTileInfos = osm.TileSource.Schema.GetTileInfos(extent, zoomScale.Value.UnitsPerPixel); noOfTiles = noOfTiles + osmTileInfos.Count(); } } Console.WriteLine(noOfTiles + " tiles in " + (noOfLayers + 1) + " layers"); //Save tiles long tilesSaved = 0; MessagingCenter.Subscribe <Application>(App.Current, "TileSavedInternal", (sender) => { //Listen for tile save updates and update the count var message = tilesSaved + " von " + noOfTiles + " Kacheln aus " + (noOfLayers + 1) + " Ebenen gespeichert"; if (noOfLayers == 0) { message = tilesSaved + " von " + noOfTiles + " Kacheln aus " + (noOfLayers + 1) + " Ebene gespeichert"; } Console.WriteLine(message); MessagingCenter.Send <Application, string>(App.Current, "TileSaved", message); if (tilesSaved >= noOfTiles - 5 || cancel) { MessagingCenter.Send <Application, string>(App.Current, "TileSaved", String.Empty); MessagingCenter.Unsubscribe <Application>(App.Current, "TileSavedInternal"); MapModel.MakeArrayOfLayers(); } }); var tasks = new List <Task>(); // Each layer has to be saved in a single thread due to database access, but we can save layers concurrently foreach (var layer in layerStack) { if (cancel) { break; } if (layer.visible) { var layerNo = Math.Max(layers.Count - layer.order, 0); var tileSource = WMSLayer.CreateTileSource(layer.url, layer.wmsLayer, "EPSG:3857"); string dbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/" + layer.title + ".mbtiles"); //extent = tileSource.Schema.Extent; var layerTask = Task.Run(async() => { //Create the database Mbtiles.CreateMbTiles(dbpath, layer, tileSource); //Populate the database foreach (var zoomScale in tileSource.Schema.Resolutions) { if (cancel) { break; } await Task.Run(async() => { var tileInfos = tileSource.Schema.GetTileInfos(extent, zoomScale.Value.UnitsPerPixel); foreach (var tileInfo in tileInfos) { if (cancel) { break; } await Task.Run(() => { tilesSaved++; saveTile(tileSource, tileInfo, dbpath, layer); }); } }); } Console.WriteLine("Saving of 1 layer complete"); }); tasks.Add(layerTask); } } //Swisstopo layer var task = Task.Run(async() => { string baselayerDbsavepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/swisstopo_pixelkarte.mbtiles"); TileLayer baselayer = WMSLayer.CreatePixelkarteWMTSTileLayer(); //Create the database var baseLayer = new BioDivCollectorXamarin.Models.DatabaseModel.Layer(); baseLayer.title = "swisstopo pixelkarte"; if (basemap == "osm") //OSM case { baselayerDbsavepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/osm.mbtiles"); baselayer = OpenStreetMap.CreateTileLayer(); //Create the database baseLayer = new BioDivCollectorXamarin.Models.DatabaseModel.Layer(); baseLayer.title = "osm"; } else if (basemap == "swissimage") //Swissimage case { baselayerDbsavepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles/swissimage.mbtiles"); baselayer = WMSLayer.CreateSwissimageWMTSTileLayer(); //Create the database baseLayer = new BioDivCollectorXamarin.Models.DatabaseModel.Layer(); baseLayer.title = "swissimage"; } Mbtiles.CreateMbTiles(baselayerDbsavepath, baseLayer, baselayer.TileSource); //Populate the database foreach (var zoomScale in baselayer.TileSource.Schema.Resolutions) { if (cancel) { break; } await Task.Run(async() => { var baseLayerTileInfos = baselayer.TileSource.Schema.GetTileInfos(extent, zoomScale.Value.UnitsPerPixel); foreach (var tileInfo in baseLayerTileInfos) { if (cancel) { break; } await Task.Run(() => { tilesSaved++; saveTile(baselayer.TileSource, tileInfo, baselayerDbsavepath, baseLayer); }); } }); } Console.WriteLine("Baselayer saved"); }); tasks.Add(task); await Task.WhenAll(tasks); }
//Mapserver layers public ObservableCollection <MapLayer> MakeArrayOfLayers() { int i = 0; //Add mbtiles layers var dirPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "mbtiles"); //Create directory if it doesn't exist if (!File.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } //Create a dictionary of all the offline files available var offlineLayers = new Dictionary <string, ILayer>(); foreach (var file in System.IO.Directory.GetFiles(dirPath)) { if (file.EndsWith(".mbtiles")) { var offlineLayer = WMSLayer.CreateOfflineLayer(file); offlineLayers.Add(offlineLayer.Name, offlineLayer); } } //Get the online layers var layers = GetLayersForMap(App.CurrentProjectId); //Create an array for adding the layers into in an ordered fashion var mapLayersTemp = new MapLayer[layers.Count]; //Add online wms layers var layerStack = layers.OrderBy(o => o.order).ToList(); foreach (var layer in layerStack) { //Now add the layers in their correct order try { var layerNo = Math.Max(layers.Count - layer.order, 0); var layerWms = WMSLayer.CreateWMSLayer(layer.url, layer.wmsLayer, "EPSG:3857", layer.title); layerWms.Opacity = layer.opacity; layerWms.Enabled = layer.visible; if (Connectivity.NetworkAccess != NetworkAccess.Internet && offlineLayers.Keys.Contains(layerWms.Name)) { //If no internet, check for saved tiles ILayer offlineLayer; offlineLayers.TryGetValue(layerWms.Name, out offlineLayer); if (offlineLayer != null) { var WmsLayer = new MapLayer(true, 0, offlineLayer); WmsLayer.Opacity = layerWms.Opacity; WmsLayer.Enabled = layerWms.Enabled; WmsLayer.LayerZ = layer.order; WmsLayer.Name = layer.title; mapLayersTemp.SetValue(WmsLayer, layerNo); i++; } } else { //If internet, read directly from WMS if (layerWms != null) { var WmsLayer = new MapLayer(true, 0, layerWms); WmsLayer.Opacity = layerWms.Opacity; WmsLayer.Enabled = layerWms.Enabled; WmsLayer.LayerZ = layer.order; WmsLayer.Name = layer.title; mapLayersTemp.SetValue(WmsLayer, layerNo); i++; } } } catch (Exception e) { Console.WriteLine(e); } } var mapLayersTempList = mapLayersTemp.ToList().GetRange(0, i); return(new ObservableCollection <MapLayer>(mapLayersTempList as List <MapLayer>)); }
/// <summary> /// Create an array of map layers: either mbtiles layers if offline and the mbtiles file exists, or direct links to the map servers /// </summary> /// <returns>An observable collection of map layers</returns> public static ObservableCollection <MapLayer> MakeArrayOfLayers() { int i = 0; //Add mbtiles layers var dirPath = Path.Combine(App.TileLocation, "mbtiles"); //Create directory if it doesn't exist if (!File.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } //Get the offline layers var offlineLayers = GetOfflineLayers(dirPath); //Get the online layers var layers = GetLayersForMap(App.CurrentProjectId); //Create an array for adding the layers into in an ordered fashion var mapLayersTemp = new MapLayer[layers.Count]; //Add online wms layers var layerStack = layers.OrderBy(o => o.order).ToList(); bool noInternet = MapModel.IsAppDisconnected(); foreach (var layer in layerStack) { //Now add the layers in their correct order try { var layerNo = Math.Max(layers.Count - layer.order, 0); bool offlineLayerExists = offlineLayers.Keys.Contains(layer.title); if (noInternet && offlineLayerExists) { //If no internet, check for saved tiles ILayer offlineLayer; offlineLayers.TryGetValue(layer.title, out offlineLayer); if (offlineLayer != null) { offlineLayer.Opacity = layer.opacity; offlineLayer.Enabled = layer.visible; var WmsLayer = new MapLayer(true, 0, offlineLayer); WmsLayer.Opacity = layer.opacity; WmsLayer.Enabled = layer.visible; WmsLayer.LayerZ = layer.order; WmsLayer.Name = layer.title; mapLayersTemp.SetValue(WmsLayer, layerNo); var path = dirPath + "/" + layer.title; FileInfo fi = new FileInfo(dirPath + "/" + layer.title + ".mbtiles"); if (fi != null) { WmsLayer.LocalStorage = fi.Length; } else { WmsLayer.LocalStorage = 0; } i++; } } else { //If internet, read directly from WMS var layerWms = WMSLayer.CreateWMSLayer(layer.url, layer.wmsLayer, "EPSG:3857", layer.title); layerWms.Opacity = layer.opacity; layerWms.Enabled = layer.visible; if (layerWms != null) { var WmsLayer = new MapLayer(true, 0, layerWms); WmsLayer.Opacity = layer.opacity; WmsLayer.Enabled = layer.visible; WmsLayer.LayerZ = layer.order; WmsLayer.Name = layer.title; mapLayersTemp.SetValue(WmsLayer, layerNo); if (offlineLayerExists) { var path = dirPath + "/" + layer.title; FileInfo fi = new FileInfo(dirPath + "/" + layer.title + ".mbtiles"); if (fi != null) { WmsLayer.LocalStorage = fi.Length; } else { WmsLayer.LocalStorage = 0; } } i++; } } } catch (Exception e) { Console.WriteLine(e); } } var mapLayersTempList = mapLayersTemp.ToList().GetRange(0, i); return(new ObservableCollection <MapLayer>(mapLayersTempList as List <MapLayer>)); }