private async void Map_MapTapped(int tileX, int tileY, int zoomLevel) { float canvasScale = 1f; float canvasSize = 768; float lineScale = 1f; //int zoomLevel = Math.Min(14, Math.Max(1, (int)sender.ZoomLevel)); //var tileAddr = MapUtil.WorldToTilePos(args.Location.Position.Longitude, args.Location.Position.Latitude, zoomLevel); System.Diagnostics.Debug.WriteLine($"{tileX} x {tileY}"); System.Diagnostics.Debug.WriteLine($"zoom: {zoomLevel}"); { var reader = await db.GetTile((int)tileX, (int)tileY, zoomLevel); if (!reader.HasRows) { textOutput.Text = DateTime.Now + ": No data"; } var tile = VectorTile.Parse(reader); if (tile.tile_data_raw != null) { PBF pbf = new PBF(tile.tile_data_raw); currentTile = ProtoBuf.Serializer.Deserialize <Tile>(new MemoryStream(tile.tile_data_raw)); if (GeometryDecoder.CanvasTileId != tile.id) { GeometryDecoder.CanvasTileId = tile.id; if (GeometryDecoder.offscreen == null) { CanvasDevice device = CanvasDevice.GetSharedDevice(); GeometryDecoder.offscreen = new CanvasRenderTarget(device, canvasSize, canvasSize, Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi *canvasScale); //GeometryDecoder.offscreenText = new CanvasRenderTarget(device, canvasSize, canvasSize, Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi * canvasScale); } //Performance benchmark Tile.Layer layer_buildings = null; Tile.Layer layer_landcover = null; Tile.Layer layer_transportation = null; Tile.Layer layer_transportation_name = null; Tile.Layer layer_housenumber = null; Tile.Layer layer_poi = null; if (currentTile.Layers.Any(l => l.Name == "building")) { layer_buildings = currentTile.Layers.Where(l => l.Name == "building").ToList()?.First(); } if (currentTile.Layers.Any(l => l.Name == "landcover")) { layer_landcover = currentTile.Layers.Where(l => l.Name == "landcover").ToList()?.First(); } if (currentTile.Layers.Any(l => l.Name == "transportation")) { layer_transportation = currentTile.Layers.Where(l => l.Name == "transportation").ToList()?.First(); } if (currentTile.Layers.Any(l => l.Name == "transportation_name")) { layer_transportation_name = currentTile.Layers.Where(l => l.Name == "transportation_name").ToList()?.First(); } if (currentTile.Layers.Any(l => l.Name == "housenumber")) { layer_housenumber = currentTile.Layers.Where(l => l.Name == "housenumber").ToList()?.First(); } if (currentTile.Layers.Any(l => l.Name == "poi")) { layer_poi = currentTile.Layers.Where(l => l.Name == "poi").ToList()?.First(); } System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); Dictionary <string, Windows.UI.Color> landColors = new Dictionary <string, Windows.UI.Color>(); landColors.Add("grass", Windows.UI.Colors.LawnGreen); landColors.Add("meadow", Windows.UI.Colors.Green); landColors.Add("wood", Windows.UI.Colors.ForestGreen); landColors.Add("forest", Windows.UI.Colors.DarkGreen); landColors.Add("park", Windows.UI.Colors.LightGreen); landColors.Add("village_green", Windows.UI.Colors.GreenYellow); landColors.Add("wetland", Windows.UI.Colors.CornflowerBlue); landColors.Add("recreation_ground", Windows.UI.Colors.LightYellow); landColors.Add("allotments", Windows.UI.Colors.Red); Dictionary <string, Tuple <Color, float, Color, float> > roadProperties = new Dictionary <string, Tuple <Color, float, Color, float> >(); roadProperties.Add("transit", new Tuple <Color, float, Color, float>(Colors.Black, 0.5f, Colors.Black, 0.5f)); roadProperties.Add("primary", new Tuple <Color, float, Color, float>(Colors.LightYellow, 3, Colors.SandyBrown, 4.5f)); roadProperties.Add("secondary", new Tuple <Color, float, Color, float>(Colors.LightYellow, 2, Colors.SandyBrown, 3f)); roadProperties.Add("tertiary", new Tuple <Color, float, Color, float>(Colors.LightYellow, 2, Colors.SandyBrown, 3f)); roadProperties.Add("minor", new Tuple <Color, float, Color, float>(Colors.WhiteSmoke, 1.8f, Colors.Gray, 2.5f)); roadProperties.Add("service", new Tuple <Color, float, Color, float>(Colors.WhiteSmoke, 1.8f, Colors.Gray, 2.5f)); roadProperties.Add("track", new Tuple <Color, float, Color, float>(Colors.LightGray, 1, Colors.Gray, 2)); roadProperties.Add("path", new Tuple <Color, float, Color, float>(Colors.LightGray, 1, Colors.Gray, 2)); roadProperties.Add("rail", new Tuple <Color, float, Color, float>(Colors.Gainsboro, 0.75f, Colors.DimGray, 1.4f)); roadProperties.Add("motorway", new Tuple <Color, float, Color, float>(Colors.Orange, 3, Colors.Red, 4.5f)); roadProperties.Add("trunk", new Tuple <Color, float, Color, float>(Colors.Orange, 3, Colors.Red, 4.5f)); GeometryDecoder.renderList = new CanvasCommandList(GeometryDecoder.offscreen); GeometryDecoder.renderText = new CanvasCommandList(GeometryDecoder.offscreen); //using (CanvasDrawingSession ds = GeometryDecoder.offscreen.CreateDrawingSession()) using (CanvasDrawingSession textDs = GeometryDecoder.renderText.CreateDrawingSession()) using (CanvasDrawingSession ds = GeometryDecoder.renderList.CreateDrawingSession()) using (CanvasActiveLayer activeLayer = ds.CreateLayer(1, new Rect(0, 0, canvasSize, canvasSize))) using (CanvasActiveLayer activeTextLayer = textDs.CreateLayer(1, new Rect(0, 0, canvasSize, canvasSize))) { ds.Antialiasing = CanvasAntialiasing.Antialiased; ds.Clear(Windows.UI.Colors.Snow); for (int it = 0; it < 1; it++) { layer_landcover?.Features.ForEach(f => { var tags = GeometryDecoder.GetTags(f, layer_landcover); var color = Colors.LightGreen; if (tags.ContainsKey("subclass")) { color = landColors.ContainsKey(tags["subclass"].StringValue) ? landColors[tags["subclass"].StringValue] : Windows.UI.Colors.LightGreen; } GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, color, color); }); layer_buildings?.Features.ForEach(f => { var tags = GeometryDecoder.GetTags(f, layer_buildings); GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, Windows.UI.Colors.SandyBrown, Windows.UI.Colors.Brown); }); List <string> tagsNames = new List <string>(); var names = layer_transportation?.Features.ConvertAll <Tuple <string, string> >(f => { var tags = GeometryDecoder.GetTags(f, layer_transportation); foreach (var t in tags) { tagsNames.Add(t.Key); } return(new Tuple <string, string>(tags.ContainsKey("class") ? tags["class"].StringValue : "", tags.ContainsKey("subclass") ? tags["subclass"].StringValue : "")); }).ToList().Distinct().ToList(); var distinctTagsNames = tagsNames.Distinct().ToList(); Tuple <Color, float, Color, float> rc = new Tuple <Color, float, Color, float>(Colors.Pink, 2, Colors.DeepPink, 2); Dictionary <int, List <Tile.Feature> > transportationFeatures = new Dictionary <int, List <Tile.Feature> >(); foreach (var f in layer_transportation.Features) { var tags = GeometryDecoder.GetTags(f, layer_transportation); int layer = tags.ContainsKey("layer") ? (int)tags["layer"].IntValue : 0; if (!transportationFeatures.ContainsKey(layer)) { transportationFeatures.Add(layer, new List <Tile.Feature>()); } transportationFeatures[layer].Add(f); } foreach (int layerNo in transportationFeatures.Keys.OrderBy(k => k)) { //background / stroke pass foreach (var f in transportationFeatures[layerNo]) { var tags = GeometryDecoder.GetTags(f, layer_transportation); if (tags.ContainsKey("class")) { if (roadProperties.ContainsKey(tags["class"].StringValue)) { var p = roadProperties[tags["class"].StringValue]; GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, 0, p.Item4 * lineScale, layerNo > 0 ? GeometryDecoder.openStrokeStyle : GeometryDecoder.normalStrokeStyle); } else { GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale, GeometryDecoder.normalStrokeStyle); } } else { GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale, GeometryDecoder.normalStrokeStyle); } } //foreground / fill pass foreach (var f in transportationFeatures[layerNo]) { var tags = GeometryDecoder.GetTags(f, layer_transportation); if (tags.ContainsKey("class")) { if (roadProperties.ContainsKey(tags["class"].StringValue)) { var p = roadProperties[tags["class"].StringValue]; if (tags["class"].StringValue == "rail" || tags["class"].StringValue == "transit") { GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0, GeometryDecoder.railStrokeStyle); // System.Diagnostics.Debug.WriteLine(t) } else { GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0, GeometryDecoder.normalStrokeStyle); } } else { System.Diagnostics.Debug.WriteLine($"Unsupported class: {tags["class"]}"); GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0, GeometryDecoder.normalStrokeStyle); } } else { GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0, GeometryDecoder.normalStrokeStyle); } } } // layer_transportation?.Features.ForEach(f => // { // var tags = GeometryDecoder.GetTags(f, layer_transportation); // if (tags.ContainsKey("class")) // { // if (roadProperties.ContainsKey(tags["class"].StringValue)) // { // var p = roadProperties[tags["class"].StringValue]; // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, 0, p.Item4 * lineScale); // } // else // { // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale); // } // } // else // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, 0, rc.Item4 * lineScale); // }); // layer_transportation?.Features.ForEach(f => // { // var tags = GeometryDecoder.GetTags(f, layer_transportation); // if (tags.ContainsKey("class")) // { // if (roadProperties.ContainsKey(tags["class"].StringValue)) // { // var p = roadProperties[tags["class"].StringValue]; // if (tags["class"].StringValue == "rail") // { // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0, GeometryDecoder.railStrokeStyle); //// System.Diagnostics.Debug.WriteLine(t) // } // else // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, p.Item1, p.Item3, p.Item2 * lineScale, 0); // } // else // { // System.Diagnostics.Debug.WriteLine($"Unsupported class: {tags["class"]}"); // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0); // } // } // else // GeometryDecoder.DrawGeometry(f, canvasSize / 4096f, ds, rc.Item1, rc.Item3, rc.Item2 * lineScale, 0); // }); layer_housenumber?.Features.ForEach(f => { var tags = GeometryDecoder.GetTags(f, layer_housenumber); string text = tags["housenumber"].StringValue; //GeometryDecoder.DrawHousenumber(f, canvasSize / 4096f, textDs, Colors.Black, Colors.White, 1, 1.2f, text); GeometryDecoder.DrawText(f, canvasSize / 4096f, textDs, Colors.Black, Colors.White, 1, 1.2f, text, 2f); }); layer_poi?.Features.ForEach(f => { var tags = GeometryDecoder.GetTags(f, layer_poi); if (tags.ContainsKey("subclass")) { string subclass = tags["subclass"].StringValue; if (icons.ContainsKey(subclass + "_11")) { GeometryDecoder.DrawIcon(f, canvasSize / 4096f, ds, icons[subclass + "_11"], Colors.Black, Colors.DarkGray); } } }); layer_transportation_name?.Features.ForEach(f => { var tags = GeometryDecoder.GetTags(f, layer_transportation_name); if (tags.ContainsKey("name")) { string text = tags["name"].StringValue; GeometryDecoder.DrawText(f, canvasSize / 4096f, textDs, Colors.Black, Colors.White, 1, 1.2f, text, 3f); } }); } } //StorageFolder storageFolder = KnownFolders.PicturesLibrary; //StorageFile file = await storageFolder.CreateFileAsync("map.bmp", CreationCollisionOption.ReplaceExisting); //var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite); //await GeometryDecoder.offscreen.SaveAsync(stream, CanvasBitmapFileFormat.Bmp); //stream.Dispose(); stopwatch.Stop(); System.Diagnostics.Debug.WriteLine($"TIME: {stopwatch.ElapsedMilliseconds} ms"); textOutput.Text = $"TIME: {stopwatch.ElapsedMilliseconds} ms"; } } else { currentTile = null; } } win2dCanvas.Invalidate(); }