private List <GeoBitmap> GetImageTiles(Matrix matrix)
        {
            List <GeoBitmap> v_ret = new List <GeoBitmap>();

            BoundingBox viewBounds = GetViewBounds(matrix);

            double[]    hgLog        = LogicalToGeoLatLon(viewBounds.XMin, viewBounds.YMax);
            double[]    bdLog        = LogicalToGeoLatLon(viewBounds.XMax, viewBounds.YMin);
            BoundingBox viewPortBbox = new BoundingBox(hgLog[0], bdLog[0]
                                                       , bdLog[1], hgLog[1]);

            BoundingBox bbox = matrix.Transform(_geomBBox);

            // Get current zoom level
            double mapSizeAtCurrentZoom = 1d * bbox.Width / _geomBBox.Width;

            int  zoom = 0;
            uint size = 0;

            while (size <= mapSizeAtCurrentZoom)
            {
                zoom++;
                if (zoom == 24)
                {
                    break;
                }
                size = BingMapsTileSystem.MapSize(zoom);
            }

            // At viewport zoom, what tile size is it ?
            double tileSizeAtZoom = 256 * mapSizeAtCurrentZoom / size;

            Trace.TraceInformation("tileSizeAtZoom: " + tileSizeAtZoom.ToString());
            if (tileSizeAtZoom < 256 && !_baseLayer.UseLowResTiles)
            {
                Trace.TraceWarning("Error in zoom calculation, tile size should be <256 but it is " + tileSizeAtZoom);
            }
            bool bTakeLowerDef = tileSizeAtZoom < 400;// _baseLayer.UseLowResTiles;

            if (bTakeLowerDef)
            {
                zoom--;
                size = BingMapsTileSystem.MapSize(zoom);
            }



            // Contruct image list
            int startX, startY, endX, endY = 0;
            int tileStartX, tileStartY, tileEndX, tileEndY = 0;

            BingMapsTileSystem.LatLongToPixelXY(viewPortBbox.YMax, viewPortBbox.XMin, zoom, out startX, out startY);
            BingMapsTileSystem.LatLongToPixelXY(viewPortBbox.YMin, viewPortBbox.XMax, zoom, out endX, out endY);
            BingMapsTileSystem.PixelXYToTileXY(startX, startY, out tileStartX, out tileStartY);
            BingMapsTileSystem.PixelXYToTileXY(endX, endY, out tileEndX, out tileEndY);

            bool stop = false;

            for (int x = tileStartX; x <= tileEndX; x++)
            {
                for (int y = tileStartY; y <= tileEndY; y++)
                {
                    if (stop)
                    {
                        break;
                    }
                    //GeoBitmap geoBmp = await _tileDownloader.DownloadTileAsync(zoom, x, y, _baseLayer);
                    GeoBitmap geoBmp = _tileDownloader.DownloadTile(zoom, x, y, _baseLayer);

                    stop = geoBmp != null && geoBmp.Exception != null && _baseLayer.StopDownloadBatchIfException;

                    if (!stop)
                    {
                        v_ret.Add(geoBmp);
                    }
                }
                if (stop)
                {
                    break;
                }
            }

            return(v_ret);
        }
		public GeoBitmap DownloadTile(int zoom, int x, int y, IBaseLayer baseLayer)
		{
			Uri uri = new Uri(baseLayer.GetTileUrl(zoom, x, y));

			GeoBitmap geoBmp = new GeoBitmap() { OriginUri = uri.ToString() };

			try
			{

				TileIndex index = new TileIndex(x, y, zoom);
				Bitmap tileImg = null;
				tileImg = GetTileFromCache(index, baseLayer.Name);
				if (tileImg != null)
				{
					geoBmp.Origin = TileOrigin.Memory;
				}
				else
				{
					tileImg = GetTileFromDisc(index, baseLayer.Name);
					if (tileImg != null)
					{
						geoBmp.Origin = TileOrigin.Disk;
						SaveTileToCache(tileImg, index, baseLayer.Name);
					}
				}

				if (tileImg == null)
				{
					HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
					request.Timeout = 500;
					request.UserAgent = USER_AGENT;
					//IWebProxy webProxy = WebRequest.DefaultWebProxy;
					//webProxy.Credentials = CredentialCache.DefaultNetworkCredentials;
					//request.Proxy = webProxy;

					try
					{
						using (WebResponse response = request.GetResponse())
						using (Stream stream = response.GetResponseStream())
						{
							tileImg = (Bitmap)Bitmap.FromStream(stream);
						}
					}
					catch (WebException webEx)
					{
						Trace.TraceWarning("Unable to download image  at " + uri.ToString() + ": " + webEx.Message);
						tileImg = new Bitmap(256, 256);
						using (Graphics g = Graphics.FromImage(tileImg))
						{
							g.Clear(Color.LightGray);
							g.DrawRectangle(Pens.Red, 0, 0, 255, 255);
							g.DrawLine(Pens.Red, 1, 1, 255, 255);
						}
						geoBmp.Exception = webEx;
					}
					finally
					{
						geoBmp.Origin = TileOrigin.Download;
						if (geoBmp.Exception == null)
						{
							SaveTileToDisc(tileImg, index, baseLayer.Name);
							SaveTileToCache(tileImg, index, baseLayer.Name);
						}
					}
				}
				geoBmp.Bitmap = tileImg;

				// what are X,Y coords for images
				int xPos, yPos = 0;
				double lat, lon = 0;
				double lat2, lon2 = 0;
				BingMapsTileSystem.TileXYToPixelXY(x, y, out xPos, out yPos);
				BingMapsTileSystem.PixelXYToLatLong(xPos, yPos, zoom, out lat, out lon);

				BingMapsTileSystem.PixelXYToLatLong(xPos + 256, yPos + 256, zoom, out lat2, out lon2);

				geoBmp.BBox = new BoundingBox(lon, lon2, lat2, lat);
				geoBmp.Index = new TileIndex(x, y, zoom);


			}
			catch (Exception ex)
			{
				geoBmp.Exception = ex;
				Trace.TraceWarning("Unable to load base layer at " + uri.ToString() + ": " + ex.Message);
			}
			return geoBmp;
		}