protected virtual void ProcessGetTileRequest(HttpContext context)
        {
            DateTime dts = DateTime.Now;

            int w = 256 * 3;
            int h = 256 * 3;
            int tileX = 0, tileY = 0, zoomLevel = 0;

            bool foundCompulsoryParameters = false;

            if (int.TryParse(context.Request["tx"], out tileX))
            {
                if (int.TryParse(context.Request["ty"], out tileY))
                {
                    if (int.TryParse(context.Request["zoom"], out zoomLevel))
                    {
                        TileUtil.NormaliseTileCoordinates(ref tileX, ref tileY, zoomLevel);
                        foundCompulsoryParameters = true;
                    }
                }
            }

            if (!foundCompulsoryParameters)
            {
                throw new InvalidOperationException("compulsory parameters 'tx','ty' or 'zoom' missing");
            }


            string cachePath = "";
            bool   useCache  = CacheOnServer;

            if (useCache)
            {
                cachePath = CreateCachePath(context, tileX, tileY, zoomLevel);
            }

            if (string.IsNullOrEmpty(cachePath))
            {
                useCache = false;
            }

            context.Response.ContentType = "application/vnd.mapbox-vector-tile";

            //is the tile cached on the server?
            if (useCache && System.IO.File.Exists(cachePath))
            {
                context.Response.Cache.SetCacheability(HttpCacheability.Public);
                context.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
                context.Response.WriteFile(cachePath);
                context.Response.Flush();
                return;
            }

            //render the tile
            List <ShapeFile> mapLayers = CreateMapLayers(context);

            if (mapLayers == null)
            {
                throw new InvalidOperationException("No Map Layers");
            }

            VectorTileGenerator tileGenerator = new VectorTileGenerator()
            {
                TileSize = this.TileSize,
                SimplificationPixelThreshold = this.SimplificationPixelThreshold
            };

            List <VectorTileLayer> tileLayers = tileGenerator.Generate(tileX, tileY, zoomLevel, mapLayers, this.OutputTileFeature);


            if (tileLayers.Count == 0)
            {
                context.Response.StatusCode = 404;
                context.Response.Flush();
                return;
            }

            //output the vectortile in Mapbox vector tile format
            using (MemoryStream ms = new MemoryStream())
            {
                EGIS.Mapbox.Vector.Tile.VectorTileParser.Encode(tileLayers, ms);
                if (useCache)
                {
                    //save the encoded tile to our cache
                    try
                    {
                        using (System.IO.FileStream fs = new FileStream(cachePath, FileMode.Create))
                        {
                            ms.WriteTo(fs);
                        }
                    }
                    catch { }
                    finally
                    {
                        ms.Seek(0, SeekOrigin.Begin);
                    }
                }

                context.Response.Cache.SetCacheability(HttpCacheability.Public);
                context.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
                ms.WriteTo(context.Response.OutputStream);
            }

            context.Response.Flush();
        }
        protected virtual void ProcessGetTileRequest(HttpContext context)
        {
            DateTime dts = DateTime.Now;

            int    w = 256 * 3;
            int    h = 256 * 3;
            int    tileX = 0, tileY = 0, zoomLevel = 0;
            PointD centerPoint = PointD.Empty;
            double zoom        = -1;

            bool foundCompulsoryParameters = false;

            if (int.TryParse(context.Request["tx"], out tileX))
            {
                if (int.TryParse(context.Request["ty"], out tileY))
                {
                    if (int.TryParse(context.Request["zoom"], out zoomLevel))
                    {
                        TileUtil.NormaliseTileCoordinates(ref tileX, ref tileY, zoomLevel);
                        centerPoint = TileUtil.GetMercatorCenterPointFromTile(tileX, tileY, zoomLevel);
                        zoom        = TileUtil.ZoomLevelToScale(zoomLevel);
                        foundCompulsoryParameters = true;
                    }
                }
            }

            if (!foundCompulsoryParameters)
            {
                throw new InvalidOperationException("compulsory parameters 'tx','ty' or 'zoom' missing");
            }


            string cachePath = "";
            bool   useCache  = CacheOnServer;

            if (useCache)
            {
                cachePath = CreateCachePath(context, tileX, tileY, zoomLevel);
            }

            if (string.IsNullOrEmpty(cachePath))
            {
                useCache = false;
            }

            context.Response.ContentType = "image/x-png";
            //is the image cached on the server?
            if (useCache && System.IO.File.Exists(cachePath))
            {
                context.Response.Cache.SetCacheability(HttpCacheability.Public);
                context.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
                context.Response.WriteFile(cachePath);
                context.Response.Flush();
                return;
            }

            //render the tile
            List <ShapeFile> mapLayers = CreateMapLayers(context);

            if (mapLayers == null)
            {
                throw new InvalidOperationException("No Map Layers");
            }
            //check if any layers are Point layers
            bool containsPointLayer = false;

            for (int n = mapLayers.Count - 1; n >= 0; --n)
            {
                if (mapLayers[n].ShapeType == ShapeType.Point || mapLayers[n].ShapeType == ShapeType.PointM || mapLayers[n].ShapeType == ShapeType.PointZ)
                {
                    containsPointLayer = true;
                }
            }
            if (containsPointLayer)
            {
                //draw to an image w x h so that labels overlapping tiles are rendered
                Bitmap bm  = new Bitmap(256, 256, SupportTransparency ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb);
                Bitmap bm2 = new Bitmap(w, h, SupportTransparency ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb);
                try
                {
                    Graphics g  = Graphics.FromImage(bm);
                    Graphics g2 = Graphics.FromImage(bm2);
                    try
                    {
                        g2.Clear(MapBackgroundColor);
                        RenderMap(g2, mapLayers, w, h, centerPoint, zoom);
                        g.DrawImage(bm2, Rectangle.FromLTRB(0, 0, 256, 256), Rectangle.FromLTRB(256, 256, 512, 512), GraphicsUnit.Pixel);

                        //perform custom painting
                    }
                    finally
                    {
                        g.Dispose();
                        g2.Dispose();
                    }
                    using (MemoryStream ms = new MemoryStream())
                    {
                        if (useCache)
                        {
                            try
                            {
                                bm.Save(cachePath, ImageFormat.Png);
                            }
                            catch { }
                        }
                        bm.Save(ms, ImageFormat.Png);

                        context.Response.Cache.SetCacheability(HttpCacheability.Public);
                        context.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
                        ms.WriteTo(context.Response.OutputStream);
                    }
                }
                finally
                {
                    bm.Dispose();
                    bm2.Dispose();
                }
            }
            else
            {
                Bitmap bm = new Bitmap(256, 256, SupportTransparency ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb);
                try
                {
                    Graphics g = Graphics.FromImage(bm);
                    try
                    {
                        g.Clear(MapBackgroundColor);
                        RenderMap(g, mapLayers, 256, 256, centerPoint, zoom);

                        //perform custom painting
                    }
                    finally
                    {
                        g.Dispose();
                    }
                    using (MemoryStream ms = new MemoryStream())
                    {
                        if (useCache)
                        {
                            try
                            {
                                bm.Save(cachePath, ImageFormat.Png);
                            }
                            catch { }
                        }
                        bm.Save(ms, ImageFormat.Png);

                        context.Response.Cache.SetCacheability(HttpCacheability.Public);
                        context.Response.Cache.SetExpires(DateTime.Now.AddDays(7));
                        ms.WriteTo(context.Response.OutputStream);
                    }
                }
                finally
                {
                    bm.Dispose();
                }
            }
            context.Response.Flush();
        }