/// <summary> /// Renders the layer /// </summary> /// <param name="g">Graphics object reference</param> /// <param name="map">Map which is rendered</param> public override void OnRender(System.Drawing.Graphics g, IMap map) { MapTransform mapTransform = new MapTransform(new PointF((float)Map.Center.X, (float)Map.Center.Y), (float)Map.PixelSize, Map.Image.Width, Map.Image.Height); string level = BruTile.Utilities.GetNearestLevel(Schema.Resolutions, Map.PixelSize); IEnumerable <TileInfo> tileInfos = Schema.GetTileInfos(mapTransform.Extent, level); var graphics = Graphics.FromImage(Image); //log.DebugFormat("Downloading tiles:"); foreach (var tileInfo in tileInfos) { var bytes = cache.Find(tileInfo.Index); if (bytes == default(byte[])) { try { //log.DebugFormat("row: {0}, column: {1}, level: {2}", tileInfo.Index.Row, tileInfo.Index.Col, tileInfo.Index.Level); bytes = TileSource.GetTile(tileInfo); cache.Add(tileInfo.Index, bytes); } catch (WebException e) { //log once per 45 seconds max if ((DateTime.Now - lastErrorLogged) > TimeSpan.FromSeconds(45)) { log.Error("Can't fetch tiles from the server", e); lastErrorLogged = DateTime.Now; } } } else { //log.DebugFormat("row: {0}, column: {1}, level: {2} (cached)", tileInfo.Index.Row, tileInfo.Index.Col, tileInfo.Index.Level); } if (bytes == null) { continue; } using (var bitmap = new Bitmap(new MemoryStream(bytes))) { var rectangle = mapTransform.WorldToMap(tileInfo.Extent.MinX, tileInfo.Extent.MinY, tileInfo.Extent.MaxX, tileInfo.Extent.MaxY); DrawTile(Schema, level, graphics, bitmap, rectangle); } } }
private IList <IFeature> GetFeaturesInTile(TileInfo tileInfo) { if (TileSource == null) { return(null); } var features = _cache?.Find(tileInfo.Index); // Is tile in cache? if (features == null) { // No, tile not in cache, so get tile data new // Calc tile offset relative to upper left corner double factor = (tileInfo.Extent.MaxX - tileInfo.Extent.MinX) / 4096.0; var tileData = TileSource.GetTile(tileInfo); if (tileData == null) { // Tile isn't in this source, so construct one from lower zoom level var maxZoom = int.Parse(BruTile.Utilities.GetNearestLevel(TileSource.Schema.Resolutions, TileSource.Schema.Resolutions[(TileSource.Schema.Resolutions.Count - 1).ToString()].UnitsPerPixel)); // Get bounds of this tile var bounds = new BoundingBox(new Point(tileInfo.Extent.MinX, tileInfo.Extent.MinY), new Point(tileInfo.Extent.MaxX, tileInfo.Extent.MaxY)); // Calc new TileInfo var zoom = int.Parse(tileInfo.Index.Level); // If zoom is ok, than there are no tile informations for this tile if (zoom <= maxZoom) { return(null); } var tileX = tileInfo.Index.Col; var tileY = tileInfo.Index.Row; while (zoom > maxZoom) { zoom--; tileX = tileX >> 1; tileY = tileY >> 1; } var newTileInfo = new TileInfo { Index = new TileIndex(tileX, tileY, zoom.ToString()) }; // Now get features for this overview tile var newFeatures = GetFeaturesInTile(newTileInfo); // Extract all features, which belong to small tile features = new List <IFeature>(); foreach (var feature in newFeatures) { if (feature is VectorTileFeature vft) { if (vft.Bounds.Intersects(bounds)) { features.Add(vft); } } } // Save for later use if (_cache != null) { _cache.Add(tileInfo.Index, features); } } if (features == null && tileData != null) { // Parse tile and convert it to a feature list Stream stream = new MemoryStream(tileData); if (IsGZipped(stream)) { stream = new GZipStream(stream, CompressionMode.Decompress); } features = VectorTileParser.Parse(tileInfo, stream); // Save for later use if (_cache != null && features.Count > 0) { _cache.Add(tileInfo.Index, features); } stream = null; } } System.Diagnostics.Debug.WriteLine($"Cached Tile Level={tileInfo.Index.Level}, Col={tileInfo.Index.Col}, Row={tileInfo.Index.Row}"); return(features); }