public Bitmap CreateImage(HttpRequestBase httpRequest) { var markers = GetMarkers(httpRequest); var paths = GetPaths(httpRequest); var otherMapProp = GetOtherQueryStringParams(httpRequest); var center = WebMercator.LatLngToPixels(otherMapProp.Latitude, otherMapProp.Longitude, otherMapProp.Zoom); var leftEdge = center["x"] - otherMapProp.Width / 2; var topEdge = center["y"] - otherMapProp.Height / 2; var tilePos = WebMercator.PixelsToTile(center["x"], center["y"]); var pos = WebMercator.PositionInTile(center["x"], center["y"]); var neTile = WebMercator.PixelsToTile(center["x"] + otherMapProp.Width / 2, center["y"] + otherMapProp.Height / 2); var swTile = WebMercator.PixelsToTile(center["x"] - otherMapProp.Width / 2, center["y"] - otherMapProp.Height / 2); // Now download all the tiles var tiles = new Dictionary <string, Dictionary <string, Stream> >(); var urls = new Dictionary <string, Dictionary <string, string> >(); var numTiles = 0; for (double x = swTile["x"]; x <= neTile["x"]; x++) { if (!tiles.ContainsKey(x.ToString())) { tiles.Add(x.ToString(), new Dictionary <string, Stream>()); urls.Add(x.ToString(), new Dictionary <string, string>()); } for (double y = swTile["y"]; y <= neTile["y"]; y++) { var url = UrlForTile(x, y, otherMapProp.Zoom, otherMapProp.TileService); tiles[x.ToString()].Add(y.ToString(), null); urls[x.ToString()].Add(y.ToString(), url); numTiles++; } } foreach (var rowUrls in urls) { foreach (var url in rowUrls.Value) { try { tiles[rowUrls.Key][url.Key] = System.Net.WebRequest.Create(url.Value).GetResponse().GetResponseStream(); } catch (Exception ex) { throw new Exception($"Calling {url.Value} is failed.", ex); } } } // Assemble all the tiles into a new image positioned as appropriate var main = new Bitmap(otherMapProp.Width, otherMapProp.Height); var graphics = Graphics.FromImage(main); graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; foreach (var ytiles in tiles) { foreach (var ytile in ytiles.Value) { var x = int.Parse(ytiles.Key); var y = int.Parse(ytile.Key); var ox = ((x - tilePos["x"]) * TILE_SIZE) - pos["x"] + (otherMapProp.Width / 2); var oy = ((y - tilePos["y"]) * TILE_SIZE) - pos["y"] + (otherMapProp.Height / 2); if (ytile.Value != null) { graphics.DrawImage(Image.FromStream(ytile.Value), Convert.ToSingle(ox), Convert.ToSingle(oy), 256.0f, 256.0f); } } } if (paths.Count > 0) { // Draw the path with ImageMagick because GD sucks as anti-aliased lines foreach (var path in paths) { var color = ColorTranslator.FromHtml("#" + path.Color); var pen = new Pen(color, Convert.ToSingle(path.Weight)); var points = new List <Point>(); for (int i = 0; i < path.Coordinates.Count; i++) { var to = WebMercator.LatLngToPixels(double.Parse(path.Coordinates[i].Latitude), double.Parse(path.Coordinates[i].Longitude), otherMapProp.Zoom); points.Add(new Point(Convert.ToInt32(to["x"] - leftEdge), Convert.ToInt32(to["y"] - topEdge))); } graphics.DrawPolygon(pen, points.ToArray()); } } // Add markers foreach (var marker in markers) { // Icons with a shadow are centered at the bottom middle pixel. // Icons with no shadow are centered in the center pixel. var px = WebMercator.LatLngToPixels(double.Parse(marker.Coordinate.Latitude), double.Parse(marker.Coordinate.Longitude), otherMapProp.Zoom); var img = Image.FromFile(marker.IconImg); float x = Convert.ToSingle(px["x"] - leftEdge - Math.Round(img.Width / 2.0)); float y = Convert.ToSingle(px["y"] - topEdge - img.Height); graphics.DrawImage(img, x, y); } return(main); }
public OtherMapProperties GetOtherQueryStringParams(HttpRequestBase httpRequest) { var otherMapProp = new OtherMapProperties(); var queryStringColl = httpRequest.QueryString; var defaultLatitude = bounds["minLat"] + ((bounds["maxLat"] - bounds["minLat"]) / 2); var defaultLongitude = bounds["minLng"] + ((bounds["maxLng"] - bounds["minLng"]) / 2); if (httpRequest["latitude"] != null) { otherMapProp.Latitude = double.Parse(httpRequest["latitude"].ToString()); otherMapProp.Longitude = double.Parse(httpRequest["longitude"].ToString()); } else { otherMapProp.Latitude = defaultLatitude; otherMapProp.Longitude = defaultLongitude; } otherMapProp.Width = httpRequest["width"] == null ? (short)300 : short.Parse(httpRequest["width"]); otherMapProp.Height = httpRequest["height"] == null ? (short)300 : short.Parse(httpRequest["height"]); // If no zoom is specified, choose a zoom level that will fit all the markers and the path if (httpRequest["zoom"] != null) { otherMapProp.Zoom = short.Parse(httpRequest["zoom"]); } else { // start at max zoom level (18) short fitZoom = 18; var doesNotFit = true; while (fitZoom > 1 && doesNotFit) { var center = WebMercator.LatLngToPixels(otherMapProp.Latitude, otherMapProp.Longitude, fitZoom); // check if the bounding rectangle fits within width/height var sw = WebMercator.LatLngToPixels(bounds["minLat"], bounds["minLng"], fitZoom); var ne = WebMercator.LatLngToPixels(bounds["maxLat"], bounds["maxLng"], fitZoom); var fitHeight = Math.Abs(ne["y"] - sw["y"]); var fitWidth = Math.Abs(ne["x"] - sw["x"]); if (fitHeight <= otherMapProp.Height && fitWidth <= otherMapProp.Width) { doesNotFit = false; } fitZoom--; } otherMapProp.Zoom = fitZoom; } //First check tileUrl from constructor if (string.IsNullOrWhiteSpace(tileService)) { var tileServices = GetDefaultTileServices(); //if tileUrl is not in constructor, try to get from querystring if (httpRequest["basemap"] != null && tileServices.ContainsKey(httpRequest["basemap"])) { otherMapProp.TileService = tileServices[httpRequest["basemap"]][0]; } else { //if tileUrl is not in constructor and not in querystring, get default from defined list otherMapProp.TileService = tileServices["osm"][0]; } } else { otherMapProp.TileService = tileService; } return(otherMapProp); }