Пример #1
0
 public void Render(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
 {
     lock (this) //gdi objects are not threadsafe
     {
         try
         {
             if (ri.tag == "area")
             {
                 RenderAreas(ti, g, way, ri);
             }
             else if (ri.tag == "line")
             {
                 RenderLines(ti, g, way, ri);
             }
             else if (ri.tag == "caption")
             {
                 RenderCaptions(ti, g, way, ri);
             }
             else if (ri.tag == "symbol")
             {
                 RenderSymbols(ti, g, way, ri);
             }
         }
         catch
         {
         }
     }
 }
Пример #2
0
        private List <RenderInfo> getMatchedRenderInfo(RequestedTileInformation ti, POI poi)
        {
            List <RenderInfo> result = new List <RenderInfo>();

            //now the easy sloppy way
            for (int i = 0; i < poi.TagIDs.Count; i++)
            {
                getMatchedRenderInfo(_renderInfoList, result, "node", ti.mapFile.Header.POITags[poi.TagIDs[i]].Key, ti.mapFile.Header.POITags[poi.TagIDs[i]].Value, ti.Zoom);
            }
            return(result);
        }
Пример #3
0
        public List <RenderInfo> GetMatchedRenderInfo(RequestedTileInformation ti, Way way)
        {
            List <RenderInfo> result = new List <RenderInfo>();

            //now the easy sloppy way
            for (int i = 0; i < way.TagIDs.Count; i++)
            {
                getMatchedRenderInfo(_renderInfoList, result, "way", ti.mapFile.Header.WayTags[way.TagIDs[i]].Key, ti.mapFile.Header.WayTags[way.TagIDs[i]].Value, ti.Zoom);
            }
            return(result);
        }
Пример #4
0
        public RequestedTileInformation GetTileInformation(long x, long y, int zoom)
        {
            RequestedTileInformation result = null;
            //select the correct subfile
            SubFile sf = (from s in _subFiles where zoom >= s.ZoomIntervalConfig.MinZoomLevel && zoom <= s.ZoomIntervalConfig.MaxZoomLevel select s).FirstOrDefault();

            if (sf != null)
            {
                result = sf.GetTileInformation(x, y, zoom);
            }
            return(result);
        }
Пример #5
0
        public void RenderAreas(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
        {
            bool drawOutline = true;

            if (way.WayDataBlocks != null && way.WayDataBlocks.Count > 0)
            {
                foreach (Way.WayData wd in way.WayDataBlocks)
                {
                    if (wd.DataBlock[0].CoordBlock.Count > 2)
                    {
                        using (GraphicsPath gp = new GraphicsPath())
                        {
                            gp.AddPolygon((from p in wd.DataBlock[0].CoordBlock select new System.Drawing.PointF((float)toRelTileX(p.Longitude, ti.X, ti.Zoom), (float)toRelTileY(p.Latitude, ti.Y, ti.Zoom))).ToArray());
                            if (wd.DataBlock.Count == 1)
                            {
                                g.FillPath(ri.Brush ?? new SolidBrush(Color.Black), gp);
                            }
                            else
                            {
                                GraphicsPath[] gpExclude = new GraphicsPath[wd.DataBlock.Count - 1];
                                for (int i = 0; i < gpExclude.Length; i++)
                                {
                                    gpExclude[i] = new GraphicsPath();
                                    Way.WayCoordinateBlock cb = wd.DataBlock[i + 1];
                                    gpExclude[i].AddPolygon((from p in cb.CoordBlock select new System.Drawing.Point((int)toRelTileX(p.Longitude, ti.X, ti.Zoom), (int)toRelTileY(p.Latitude, ti.Y, ti.Zoom))).ToArray());
                                }
                                Region region = new Region(gp);
                                for (int i = 0; i < gpExclude.Length; i++)
                                {
                                    region.Exclude(gpExclude[i]);
                                }
                                g.FillRegion(ri.Brush ?? new SolidBrush(Color.White), region);
                                for (int i = 0; i < gpExclude.Length; i++)
                                {
                                    if (drawOutline && ri.Pen != null)
                                    {
                                        g.DrawPolygon(ri.Pen, gpExclude[i].PathPoints);
                                    }
                                    gpExclude[i].Dispose();
                                }
                            }
                            if (drawOutline && ri.Pen != null)
                            {
                                g.DrawPolygon(ri.Pen, gp.PathPoints);
                            }
                        }
                    }
                }
            }
        }
Пример #6
0
        public void RenderCaptions(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
        {
            int lat;
            int lon;

            if (way.LabelLatitude != null && way.LabelLongitude != null)
            {
                lat = (int)way.LabelLatitude;
                lon = (int)way.LabelLongitude;
            }
            else
            {
                lat = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Latitude);
                lon = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Longitude);
            }

            using (Font fnt = new Font(FontFamily.GenericSerif, string.IsNullOrEmpty(ri.font_size) ? (float)10.0 : (float)Utils.Conversion.StringToDouble(ri.font_size), ri.font_style == "bold" ? FontStyle.Bold : FontStyle.Regular))
                using (StringFormat sf = new StringFormat())
                {
                    sf.Alignment     = StringAlignment.Center;
                    sf.LineAlignment = StringAlignment.Center;
                    float x = (float)toRelTileX(lon, ti.X, ti.Zoom);
                    float y = (float)toRelTileY(lat, ti.Y, ti.Zoom);
                    if (x > 0 && x < 256 && y > 0 && y < 256)
                    {
                        SizeF s  = g.MeasureString(way.Name, fnt);
                        float w2 = (s.Width / 2.0f);
                        float h2 = (s.Height / 2.0f);
                        if (x + w2 > 256)
                        {
                            x = 256 - w2;
                        }
                        if (y + h2 > 256)
                        {
                            y = 256 - h2;
                        }
                        if (x < w2)
                        {
                            x = w2;
                        }
                        if (y < h2)
                        {
                            y = h2;
                        }

                        g.DrawString(way.Name, fnt, ri.Brush ?? new SolidBrush(Color.Black), x, y, sf);
                    }
                }
        }
Пример #7
0
        public void RenderSymbols(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
        {
            int lat;
            int lon;

            if (way.LabelLatitude != null && way.LabelLongitude != null)
            {
                lat = (int)way.LabelLatitude;
                lon = (int)way.LabelLongitude;
            }
            else
            {
                lat = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Latitude);
                lon = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Longitude);
            }
            g.DrawImageUnscaled(ri.Symbol, (int)toRelTileX(lon, ti.X, ti.Zoom), (int)toRelTileY(lat, ti.Y, ti.Zoom));
        }
Пример #8
0
 public void RenderLines(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
 {
     if (way.WayDataBlocks != null && way.WayDataBlocks.Count > 0)
     {
         bool  nDone = false;
         float f     = getPaintZoomLevel(ti.Zoom);
         foreach (Way.WayData wd in way.WayDataBlocks)
         {
             System.Drawing.PointF[] pa = (from p in wd.DataBlock[0].CoordBlock select new System.Drawing.PointF((float)toRelTileX(p.Longitude, ti.X, ti.Zoom), (float)toRelTileY(p.Latitude, ti.Y, ti.Zoom))).ToArray();
             using (GraphicsPath gp = new GraphicsPath())
             {
                 for (int i = 0; i < pa.Length - 1; i++)
                 {
                     gp.AddLine(pa[i], pa[i + 1]);
                 }
                 Pen p = ri.Pen ?? new Pen(Color.Black);
                 p.Width = ri.fstroke_width * f;
                 g.DrawPath(p, gp);
                 if (ri.FillPen != null)
                 {
                     ri.FillPen.Width = ri.fstroke_width * f * 0.8f;
                     g.DrawPath(ri.FillPen, gp);
                 }
                 if (!string.IsNullOrEmpty(way.Name) && p.Width > 6.0f && !nDone)
                 {
                     nDone = true; //only once per tile is enough I think
                     using (Font fnt = new Font(FontFamily.GenericSerif, p.Width))
                     {
                         //determine angle of polyline (use start and endpoint?)
                         //if wrong (text upside down), then reverse polyline
                         PointF p1 = pa[0];
                         PointF p2 = pa[pa.Length - 1];
                         if (p1.X > p2.X)
                         {
                             gp.Reverse();
                         }
                         g.DrawString(way.Name, fnt, _fixedTextBrush, TextPathAlign.Center, TextPathPosition.CenterPath, 100, 0, gp);
                     }
                 }
             }
         }
     }
 }
Пример #9
0
        public BitmapImage GetTileBitmap(Uri uri)
        {
            BitmapImage result = null;

#if DEBUG2
            lock (this)
            {
#endif
            try
            {
                string[] parts = uri.AbsoluteUri.Split(new char[] { '/', '.' }, StringSplitOptions.RemoveEmptyEntries);
                int      zoom  = int.Parse(parts[4]);
                long     x     = long.Parse(parts[5]);
                long     y     = long.Parse(parts[6]);
                double   lat   = MapFile.GetLatitude(y, zoom);
                double   lon   = MapFile.GetLongitude(x, zoom);
                var      mfs   = from m in _mapFiles where lat >= m.Header.MinLat && lat < m.Header.MaxLat && lon >= m.Header.MinLon && lon < m.Header.MaxLon select m;
                List <RequestedTileInformation> tis = new List <RequestedTileInformation>();
                foreach (MapFile mf in mfs)
                {
                    RequestedTileInformation ti = mf.GetTileInformation(x, y, zoom);
                    if (ti != null)
                    {
                        tis.Add(ti);
                    }
                }
                if (tis.Count > 0)
                {
                    result = TileRenderer.GetTileBitmap(tis);
                }
            }
            catch
            {
            }
#if DEBUG2
        }
#endif
            return(result);
        }
Пример #10
0
 public void Render(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
 {
     lock (this) //gdi objects are not threadsafe
     {
         try
         {
             if (ri.tag == "area")
             {
                 RenderAreas(ti, g, way, ri);
             }
             else if (ri.tag == "line")
             {
                 RenderLines(ti, g, way, ri);
             }
             else if (ri.tag == "caption")
             {
                 RenderCaptions(ti, g, way, ri);
             }
             else if (ri.tag == "symbol")
             {
                 RenderSymbols(ti, g, way, ri);
             }
         }
         catch
         {
         }
     }
 }
Пример #11
0
 private List<RenderInfo> getMatchedRenderInfo(RequestedTileInformation ti, POI poi)
 {
     List<RenderInfo> result = new List<RenderInfo>();
     //now the easy sloppy way
     for (int i = 0; i < poi.TagIDs.Count; i++)
     {
         getMatchedRenderInfo(_renderInfoList, result, "node", ti.mapFile.Header.POITags[poi.TagIDs[i]].Key, ti.mapFile.Header.POITags[poi.TagIDs[i]].Value, ti.Zoom);
     }
     return result;
 }
Пример #12
0
 public List<RenderInfo> GetMatchedRenderInfo(RequestedTileInformation ti, Way way)
 {
     List<RenderInfo> result = new List<RenderInfo>();
     //now the easy sloppy way
     for (int i = 0; i < way.TagIDs.Count; i++ )
     {
         getMatchedRenderInfo(_renderInfoList, result, "way",  ti.mapFile.Header.WayTags[way.TagIDs[i]].Key, ti.mapFile.Header.WayTags[way.TagIDs[i]].Value, ti.Zoom);
     }
     return result;
 }
Пример #13
0
 public void RenderSymbols(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
 {
     int lat;
     int lon;
     if (way.LabelLatitude != null && way.LabelLongitude != null)
     {
         lat = (int)way.LabelLatitude;
         lon = (int)way.LabelLongitude;
     }
     else
     {
         lat = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Latitude);
         lon = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Longitude);
     }
     g.DrawImageUnscaled(ri.Symbol, (int)toRelTileX(lon, ti.X, ti.Zoom), (int)toRelTileY(lat, ti.Y, ti.Zoom));
 }
Пример #14
0
        public void Render(RequestedTileInformation ti, Graphics g, POI poi)
        {
            lock (this) //gdi objects are not threadsafe
            {
                try
                {
                    List <RenderInfo> ris = getMatchedRenderInfo(ti, poi);

                    bool cDone = false;
                    bool sDone = false;
                    foreach (RenderInfo ri in ris)
                    {
                        if (ri.tag == "circle")
                        {
                            break;
                        }
                    }
                    foreach (RenderInfo ri in ris)
                    {
                        if (ri.tag == "caption" && !cDone)
                        {
                            using (Font fnt = new Font(FontFamily.GenericSerif, string.IsNullOrEmpty(ri.font_size) ? (float)10.0 : (float)Utils.Conversion.StringToDouble(ri.font_size), ri.font_style == "bold" ? FontStyle.Bold : FontStyle.Regular))
                                using (StringFormat sf = new StringFormat())
                                {
                                    sf.Alignment     = StringAlignment.Center;
                                    sf.LineAlignment = StringAlignment.Center;
                                    float x = (float)toRelTileX(poi.Longitude, ti.X, ti.Zoom);
                                    float y = (float)toRelTileY(poi.Latitude, ti.Y, ti.Zoom);
                                    if (x > 0 && x < 256 && y > 0 && y < 256)
                                    {
                                        SizeF s  = g.MeasureString(poi.Name, fnt);
                                        float w2 = (s.Width / 2.0f);
                                        float h2 = (s.Height / 2.0f);
                                        if (x + w2 > 256)
                                        {
                                            x = 256 - w2;
                                        }
                                        if (y + h2 > 256)
                                        {
                                            y = 256 - h2;
                                        }
                                        if (x < w2)
                                        {
                                            x = w2;
                                        }
                                        if (y < h2)
                                        {
                                            y = h2;
                                        }
                                        g.DrawString(poi.Name, fnt, ri.Brush ?? _fixedTextBrush, x, y, sf);
                                        //g.DrawRectangle(new Pen(Color.Red, 1), x-w2, y-h2, s.Width, s.Height);
                                    }
                                }
                            cDone = true;
                        }
                        else if (ri.tag == "symbol" && !sDone && ri.Symbol != null)
                        {
                            g.DrawImageUnscaled(ri.Symbol, (int)toRelTileX(poi.Longitude, ti.X, ti.Zoom), (int)toRelTileY(poi.Latitude, ti.Y, ti.Zoom));
                            sDone = true;
                        }
                    }
                }
                catch
                {
                }
            }
        }
Пример #15
0
        public void Render(RequestedTileInformation ti, Graphics g, POI poi)
        {
            lock (this) //gdi objects are not threadsafe
            {
                try
                {
                    List<RenderInfo> ris = getMatchedRenderInfo(ti, poi);

                    bool cDone = false;
                    bool sDone = false;
                    foreach (RenderInfo ri in ris)
                    {
                        if (ri.tag == "circle")
                        {
                            break;
                        }
                    }
                    foreach (RenderInfo ri in ris)
                    {
                        if (ri.tag == "caption" && !cDone)
                        {
                            using (Font fnt = new Font(FontFamily.GenericSerif, string.IsNullOrEmpty(ri.font_size) ? (float)10.0 : (float)Utils.Conversion.StringToDouble(ri.font_size), ri.font_style == "bold" ? FontStyle.Bold : FontStyle.Regular))
                            using (StringFormat sf = new StringFormat())
                            {
                                sf.Alignment = StringAlignment.Center;
                                sf.LineAlignment = StringAlignment.Center;
                                float x = (float)toRelTileX(poi.Longitude, ti.X, ti.Zoom);
                                float y = (float)toRelTileY(poi.Latitude, ti.Y, ti.Zoom);
                                if (x > 0 && x < 256 && y > 0 && y < 256)
                                {
                                    SizeF s = g.MeasureString(poi.Name, fnt);
                                    float w2 = (s.Width / 2.0f);
                                    float h2 = (s.Height / 2.0f);
                                    if (x + w2 > 256) x = 256 - w2;
                                    if (y + h2 > 256) y = 256 - h2;
                                    if (x < w2) x = w2;
                                    if (y < h2) y = h2;
                                    g.DrawString(poi.Name, fnt, ri.Brush ?? _fixedTextBrush, x, y, sf);
                                    //g.DrawRectangle(new Pen(Color.Red, 1), x-w2, y-h2, s.Width, s.Height);
                                }
                            }
                            cDone = true;
                        }
                        else if (ri.tag == "symbol" && !sDone && ri.Symbol != null)
                        {
                            g.DrawImageUnscaled(ri.Symbol, (int)toRelTileX(poi.Longitude, ti.X, ti.Zoom), (int)toRelTileY(poi.Latitude, ti.Y, ti.Zoom));
                            sDone = true;
                        }
                    }
                }
                catch
                {
                }
            }
        }
Пример #16
0
 public void RenderAreas(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
 {
     bool drawOutline = true;
     if (way.WayDataBlocks != null && way.WayDataBlocks.Count > 0)
     {
         foreach (Way.WayData wd in way.WayDataBlocks)
         {
             if (wd.DataBlock[0].CoordBlock.Count > 2)
             {
                 using (GraphicsPath gp = new GraphicsPath())
                 {
                     gp.AddPolygon((from p in wd.DataBlock[0].CoordBlock select new System.Drawing.PointF((float)toRelTileX(p.Longitude, ti.X, ti.Zoom), (float)toRelTileY(p.Latitude, ti.Y, ti.Zoom))).ToArray());
                     if (wd.DataBlock.Count == 1)
                     {
                         g.FillPath(ri.Brush ?? new SolidBrush(Color.Black), gp);
                     }
                     else
                     {
                         GraphicsPath[] gpExclude = new GraphicsPath[wd.DataBlock.Count - 1];
                         for (int i = 0; i < gpExclude.Length; i++)
                         {
                             gpExclude[i] = new GraphicsPath();
                             Way.WayCoordinateBlock cb = wd.DataBlock[i + 1];
                             gpExclude[i].AddPolygon((from p in cb.CoordBlock select new System.Drawing.Point((int)toRelTileX(p.Longitude, ti.X, ti.Zoom), (int)toRelTileY(p.Latitude, ti.Y, ti.Zoom))).ToArray());
                         }
                         Region region = new Region(gp);
                         for (int i = 0; i < gpExclude.Length; i++)
                         {
                             region.Exclude(gpExclude[i]);
                         }
                         g.FillRegion(ri.Brush ?? new SolidBrush(Color.White), region);
                         for (int i = 0; i < gpExclude.Length; i++)
                         {
                             if (drawOutline && ri.Pen != null)
                             {
                                 g.DrawPolygon(ri.Pen, gpExclude[i].PathPoints);
                             }
                             gpExclude[i].Dispose();
                         }
                     }
                     if (drawOutline && ri.Pen != null)
                     {
                         g.DrawPolygon(ri.Pen, gp.PathPoints);
                     }
                 }
             }
         }
     }
 }
Пример #17
0
 public void RenderLines(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
 {
     if (way.WayDataBlocks != null && way.WayDataBlocks.Count > 0)
     {
         bool nDone = false;
         float f = getPaintZoomLevel(ti.Zoom);
         foreach (Way.WayData wd in way.WayDataBlocks)
         {
             System.Drawing.PointF[] pa = (from p in wd.DataBlock[0].CoordBlock select new System.Drawing.PointF((float)toRelTileX(p.Longitude, ti.X, ti.Zoom), (float)toRelTileY(p.Latitude, ti.Y, ti.Zoom))).ToArray();
             using (GraphicsPath gp = new GraphicsPath())
             {
                 for (int i = 0; i < pa.Length - 1; i++)
                 {
                     gp.AddLine(pa[i], pa[i + 1]);
                 }
                 Pen p = ri.Pen ?? new Pen(Color.Black);
                 p.Width = ri.fstroke_width * f;
                 g.DrawPath(p, gp);
                 if (ri.FillPen != null)
                 {
                     ri.FillPen.Width = ri.fstroke_width * f * 0.8f;
                     g.DrawPath(ri.FillPen, gp);
                 }
                 if (!string.IsNullOrEmpty(way.Name) && p.Width > 6.0f && !nDone)
                 {
                     nDone = true; //only once per tile is enough I think
                     using (Font fnt = new Font(FontFamily.GenericSerif, p.Width))
                     {
                         //determine angle of polyline (use start and endpoint?)
                         //if wrong (text upside down), then reverse polyline
                         PointF p1 = pa[0];
                         PointF p2 = pa[pa.Length - 1];
                         if (p1.X > p2.X)
                         {
                             gp.Reverse();
                         }
                         g.DrawString(way.Name, fnt, _fixedTextBrush, TextPathAlign.Center, TextPathPosition.CenterPath, 100, 0, gp);
                     }
                 }
             }
         }
     }
 }
Пример #18
0
        public void RenderCaptions(RequestedTileInformation ti, Graphics g, Way way, RenderInfo ri)
        {
            int lat;
            int lon;
            if (way.LabelLatitude != null && way.LabelLongitude != null)
            {
                lat = (int)way.LabelLatitude;
                lon = (int)way.LabelLongitude;
            }
            else
            {
                lat = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Latitude);
                lon = (int)way.WayDataBlocks[0].DataBlock[0].CoordBlock.Average(x => x.Longitude);
            }

            using (Font fnt = new Font(FontFamily.GenericSerif, string.IsNullOrEmpty(ri.font_size) ? (float)10.0 : (float)Utils.Conversion.StringToDouble(ri.font_size), ri.font_style == "bold" ? FontStyle.Bold : FontStyle.Regular))
            using (StringFormat sf = new StringFormat())
            {
                sf.Alignment = StringAlignment.Center;
                sf.LineAlignment = StringAlignment.Center;
                float x = (float)toRelTileX(lon, ti.X, ti.Zoom);
                float y = (float)toRelTileY(lat, ti.Y, ti.Zoom);
                if (x > 0 && x < 256 && y > 0 && y < 256)
                {
                    SizeF s = g.MeasureString(way.Name, fnt);
                    float w2 = (s.Width / 2.0f);
                    float h2 = (s.Height / 2.0f);
                    if (x + w2 > 256) x = 256 - w2;
                    if (y + h2 > 256) y = 256 - h2;
                    if (x < w2) x = w2;
                    if (y < h2) y = h2;

                    g.DrawString(way.Name, fnt, ri.Brush ?? new SolidBrush(Color.Black), x, y, sf);
                }
            }
        }
Пример #19
0
        public RequestedTileInformation GetTileInformation(long x, long y, int zoom)
        {
            RequestedTileInformation ti = new RequestedTileInformation();
            try
            {
                ti.mapFile = _mapFile;
                ti.X = x;
                ti.Y = y;
                ti.Zoom = zoom;
                ti.ZoomIntervalConfig = this.ZoomIntervalConfig;

                if (zoom < ZoomIntervalConfig.BaseZoomLevel)
                {
                    // calculate the XY numbers of the upper left and lower right sub-tiles
                    int zoomLevelDifference = ZoomIntervalConfig.BaseZoomLevel - zoom;
                    ti.FromBaseTileX = x << zoomLevelDifference;
                    ti.FromBaseTileY = y << zoomLevelDifference;
                    ti.ToBaseTileX = ti.FromBaseTileX + (1 << zoomLevelDifference) - 1;
                    ti.ToBaseTileY = ti.FromBaseTileY + (1 << zoomLevelDifference) - 1;
                    ti.UseSubTileBitmapMask = false;
                }
                else if (zoom > ZoomIntervalConfig.BaseZoomLevel)
                {
                    // calculate the XY numbers of the parent base tile
                    int zoomLevelDifference = zoom - ZoomIntervalConfig.BaseZoomLevel;
                    ti.FromBaseTileX = x >> zoomLevelDifference;
                    ti.FromBaseTileY = y >> zoomLevelDifference;
                    ti.ToBaseTileX = ti.FromBaseTileX;
                    ti.ToBaseTileY = ti.FromBaseTileY;
                    ti.UseSubTileBitmapMask = true;

                    //calculate ti.SubTileBitmapMask
                    if (zoomLevelDifference == 1)
                    {
                        if (x % 2 == 0 && y % 2 == 0)
                        {
                            // upper left quadrant
                            ti.SubTileBitmapMask = 0xcc00;
                        }
                        else if (x % 2 == 1 && y % 2 == 0)
                        {
                            // upper right quadrant
                            ti.SubTileBitmapMask = 0x3300;
                        }
                        else if (x % 2 == 0 && y % 2 == 1)
                        {
                            // lower left quadrant
                            ti.SubTileBitmapMask = 0xcc;
                        }
                        else
                        {
                            // lower right quadrant
                            ti.SubTileBitmapMask = 0x33;
                        }
                    }
                    else
                    {
                        // calculate the XY numbers of the second level sub-tile
                        long subtileX = x >> (zoomLevelDifference - 2);
                        long subtileY = y >> (zoomLevelDifference - 2);

                        // calculate the XY numbers of the parent tile
                        long parentTileX = subtileX >> 1;
                        long parentTileY = subtileY >> 1;

                        // determine the correct bitmask for all 16 sub-tiles
                        if (parentTileX % 2 == 0 && parentTileY % 2 == 0)
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x8000;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x4000;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x800;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x400;
                            }
                        }
                        else if (parentTileX % 2 == 1 && parentTileY % 2 == 0)
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x2000;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x1000;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x200;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x100;
                            }
                        }
                        else if (parentTileX % 2 == 0 && parentTileY % 2 == 1)
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x80;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x40;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x8;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x4;
                            }
                        }
                        else
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x20;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x10;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x2;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x1;
                            }
                        }
                    }

                }
                else
                {
                    // use the tile XY numbers of the requested tile
                    ti.FromBaseTileX = x;
                    ti.FromBaseTileY = y;
                    ti.ToBaseTileX = ti.FromBaseTileX;
                    ti.ToBaseTileY = ti.FromBaseTileY;
                    ti.UseSubTileBitmapMask = false;
                }

                ti.FromBlockX = Math.Max(ti.FromBaseTileX - MinX, 0);
                ti.FromBlockY = Math.Max(ti.FromBaseTileY - MinY, 0);
                ti.ToBlockX = Math.Min(ti.ToBaseTileX - MinX, MaxX);
                ti.ToBlockY = Math.Min(ti.ToBaseTileY - MinY, MaxY);

                ti.POIs = new List<POI>();
                ti.Ways = new List<Way>();
                for (long row = ti.FromBlockY; row <= ti.ToBlockY; row++)
                {
                    for (long column = ti.FromBlockX; column <= ti.ToBlockX; column++)
                    {
                        // calculate the actual block number of the needed block in the file
                        long blockNumber = (row * (MaxX - MinX + 1)) + column;
                        if (blockNumber >= _tileAbsOffsets.Length || _tileAbsOffsets[blockNumber] == 0 || _tileAbsOffsets[blockNumber] >= ZoomIntervalConfig.SubFileSize)
                        {
                            continue;
                        }

                        long blockSize;
                        if (blockNumber < _tileAbsOffsets.Length - 1)
                        {
                            blockSize = _tileAbsOffsets[blockNumber + 1] - _tileAbsOffsets[blockNumber];
                        }
                        else
                        {
                            blockSize = ZoomIntervalConfig.SubFileSize - _tileAbsOffsets[blockNumber] + 1;
                        }
                        if (blockSize < 1)
                        {
                            continue;
                        }

                        ti.TileDataBuffer = new byte[blockSize];
                        _mapFile.ReadBuffer(ti.TileDataBuffer, _tileAbsOffsets[blockNumber] + ZoomIntervalConfig.AbsStartPositionSubFile, (int)blockSize);
                        using (ti.TileDataBufferStream = new System.IO.MemoryStream(ti.TileDataBuffer))
                        {
                            // calculate the top-left coordinates of the underlying tile
                            ti.TileLatitudeDeg = MapFile.GetLatitude(MinY + row, ZoomIntervalConfig.BaseZoomLevel);
                            ti.TileLongitudeDeg = MapFile.GetLongitude(MinX + column, ZoomIntervalConfig.BaseZoomLevel);
                            ti.TileLatitude = (int)(ti.TileLatitudeDeg * 1000000);
                            ti.TileLongitude = (int)(ti.TileLongitudeDeg * 1000000);

                            if (_mapFile.Header.DebugInformationPresent)
                            {
                                ti.TileDataBufferStream.Position = 32;
                            }

                            //get the zoom table
                            int rows = ZoomIntervalConfig.MaxZoomLevel - ZoomIntervalConfig.MinZoomLevel + 1;
                            ti.ZoomTable = new int[rows, 2];

                            int cumulatedNumberOfPois = 0;
                            int cumulatedNumberOfWays = 0;

                            for (int r = 0; r < rows; r++)
                            {
                                cumulatedNumberOfPois += (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                cumulatedNumberOfWays += (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);

                                ti.ZoomTable[r, 0] = cumulatedNumberOfPois;
                                ti.ZoomTable[r, 1] = cumulatedNumberOfWays;
                            }
                            ti.ZoomTableRow = zoom - ZoomIntervalConfig.MinZoomLevel;
                            ti.PoisOnQueryZoomLevel = ti.ZoomTable[ti.ZoomTableRow, 0];
                            ti.WaysOnQueryZoomLevel = ti.ZoomTable[ti.ZoomTableRow, 1];

                            ti.FirstWayOffset = MapFile.ReadVBEUint(ti.TileDataBufferStream);
                            ti.FirstWayOffset += ti.TileDataBufferStream.Position;

                            //get POIs
                            for (int p = 0; p < ti.PoisOnQueryZoomLevel; p++)
                            {
                                POI poi = new POI();

                                if (_mapFile.Header.DebugInformationPresent)
                                {
                                    ti.TileDataBufferStream.Position += 32;
                                }

                                //lat/lon
                                poi.Latitude = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                poi.Longitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                //layer and tag ids
                                poi.TagIDs = new List<int>();
                                byte b = (byte)ti.TileDataBufferStream.ReadByte();
                                poi.Layer = b >> 4;
                                int tagCount = (b & 0x0F);
                                for (int t = 0; t < tagCount; t++)
                                {
                                    poi.TagIDs.Add((int)MapFile.ReadVBEUint(ti.TileDataBufferStream));
                                }

                                //flags
                                b = (byte)ti.TileDataBufferStream.ReadByte();
                                if ((b & 0x80) == 0x80)
                                {
                                    poi.Name = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    poi.Name = null;
                                }
                                if ((b & 0x40) == 0x40)
                                {
                                    poi.HouseNumber = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    poi.HouseNumber = null;
                                }
                                if ((b & 0x20) == 0x20)
                                {
                                    poi.Elevation = MapFile.ReadVBESint(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    poi.Elevation = null;
                                }

                                ti.POIs.Add(poi);
                            }

                            ti.TileDataBufferStream.Position = ti.FirstWayOffset;

                            //get ways
                            for (int w = 0; w < ti.WaysOnQueryZoomLevel; w++)
                            {
                                Way way = new Way();

                                if (_mapFile.Header.DebugInformationPresent)
                                {
                                    ti.TileDataBufferStream.Position += 32;
                                }

                                int wayDataSize = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                int subTileBitmap = MapFile.ReadUInt16(ti.TileDataBufferStream);

                                if (ti.UseSubTileBitmapMask)
                                {
                                    // check if the way is inside the requested tile
                                    if ((ti.SubTileBitmapMask & subTileBitmap) == 0)
                                    {
                                        // skip the rest of the way and continue with the next way
                                        ti.TileDataBufferStream.Position += (wayDataSize - 2);
                                        continue;
                                    }
                                }

                                //layer and tags
                                way.TagIDs = new List<int>();
                                byte b = (byte)ti.TileDataBufferStream.ReadByte();
                                way.Layer = b >> 4;
                                int tagCount = (b & 0x0F);
                                for (int t = 0; t < tagCount; t++)
                                {
                                    way.TagIDs.Add((int)MapFile.ReadVBEUint(ti.TileDataBufferStream));
                                }

                                //feature bytes
                                b = (byte)ti.TileDataBufferStream.ReadByte();
                                if ((b & 0x80) == 0x80)
                                {
                                    way.Name = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.Name = null;
                                }
                                if ((b & 0x40) == 0x40)
                                {
                                    way.HouseNumber = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.HouseNumber = null;
                                }
                                if ((b & 0x20) == 0x20)
                                {
                                    way.Reference = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.Reference = null;
                                }
                                if ((b & 0x10) == 0x10)
                                {
                                    way.LabelLatitude = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                    way.LabelLongitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.LabelLatitude = null;
                                    way.LabelLongitude = null;
                                }

                                int numberOfBlocks;
                                if ((b & 0x08) == 0x08)
                                {
                                    numberOfBlocks = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    numberOfBlocks = 1;
                                }

                                bool doubleEncoding = ((b & 0x04) == 0x04);
                                way.WayDataBlocks = new List<Way.WayData>();
                                for (int wb = 0; wb < numberOfBlocks; wb++)
                                {
                                    //read: way data
                                    Way.WayData wd = new Way.WayData();

                                    int numberOfWayCoordBlocks = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                    wd.DataBlock = new List<Way.WayCoordinateBlock>();
                                    for (int wcd = 0; wcd < numberOfWayCoordBlocks; wcd++)
                                    {
                                        //read way coordinate block
                                        Way.WayCoordinateBlock coordBlock = new Way.WayCoordinateBlock();
                                        coordBlock.CoordBlock = new List<Way.WayCoordinate>();

                                        int nodesCount = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                        //Way.WayCoordinate diffwc = wc;
                                        if (doubleEncoding)
                                        {
                                            // get the first way node latitude single-delta offset (VBE-S)
                                            int wayNodeLatitude = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                            // get the first way node longitude single-delta offset (VBE-S)
                                            int wayNodeLongitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                            // store the first way node
                                            Way.WayCoordinate wc = new Way.WayCoordinate();
                                            wc.Latitude = wayNodeLatitude;
                                            wc.Longitude = wayNodeLongitude;
                                            coordBlock.CoordBlock.Add(wc);

                                            int previousSingleDeltaLatitude = 0;
                                            int previousSingleDeltaLongitude = 0;

                                            for (int n = 1; n < nodesCount; n++)
                                            {
                                                // get the way node latitude double-delta offset (VBE-S)
                                                int doubleDeltaLatitude = MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                // get the way node longitude double-delta offset (VBE-S)
                                                int doubleDeltaLongitude = MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                int singleDeltaLatitude = doubleDeltaLatitude + previousSingleDeltaLatitude;
                                                int singleDeltaLongitude = doubleDeltaLongitude + previousSingleDeltaLongitude;

                                                wayNodeLatitude = wayNodeLatitude + singleDeltaLatitude;
                                                wayNodeLongitude = wayNodeLongitude + singleDeltaLongitude;

                                                Way.WayCoordinate wcNext = new Way.WayCoordinate();
                                                wcNext.Latitude = wayNodeLatitude;
                                                wcNext.Longitude = wayNodeLongitude;
                                                coordBlock.CoordBlock.Add(wcNext);

                                                previousSingleDeltaLatitude = singleDeltaLatitude;
                                                previousSingleDeltaLongitude = singleDeltaLongitude;
                                            }
                                        }
                                        else
                                        {

                                            // get the first way node latitude single-delta offset (VBE-S)
                                            int wayNodeLatitude = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                            // get the first way node longitude single-delta offset (VBE-S)
                                            int wayNodeLongitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                            // store the first way node
                                            Way.WayCoordinate wc = new Way.WayCoordinate();
                                            wc.Latitude = wayNodeLatitude;
                                            wc.Longitude = wayNodeLongitude;
                                            coordBlock.CoordBlock.Add(wc);

                                            for (int n = 1; n < nodesCount; n++)
                                            {
                                                // get the way node latitude offset (VBE-S)
                                                wayNodeLatitude = wayNodeLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                // get the way node longitude offset (VBE-S)
                                                wayNodeLongitude = wayNodeLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                Way.WayCoordinate wcNext = new Way.WayCoordinate();
                                                wcNext.Latitude = wayNodeLatitude;
                                                wcNext.Longitude = wayNodeLongitude;
                                                coordBlock.CoordBlock.Add(wcNext);
                                            }
                                        }

                                        wd.DataBlock.Add(coordBlock);
                                    }

                                    way.WayDataBlocks.Add(wd);
                                }

                                ti.Ways.Add(way);
                            }
                        }
                    }
                }
                ti.TileDataBuffer = null; //memory can be released
            }
            catch
            {
                ti = null;
            }
            return ti;
        }
Пример #20
0
        public RequestedTileInformation GetTileInformation(long x, long y, int zoom)
        {
            RequestedTileInformation ti = new RequestedTileInformation();

            try
            {
                ti.mapFile            = _mapFile;
                ti.X                  = x;
                ti.Y                  = y;
                ti.Zoom               = zoom;
                ti.ZoomIntervalConfig = this.ZoomIntervalConfig;

                if (zoom < ZoomIntervalConfig.BaseZoomLevel)
                {
                    // calculate the XY numbers of the upper left and lower right sub-tiles
                    int zoomLevelDifference = ZoomIntervalConfig.BaseZoomLevel - zoom;
                    ti.FromBaseTileX        = x << zoomLevelDifference;
                    ti.FromBaseTileY        = y << zoomLevelDifference;
                    ti.ToBaseTileX          = ti.FromBaseTileX + (1 << zoomLevelDifference) - 1;
                    ti.ToBaseTileY          = ti.FromBaseTileY + (1 << zoomLevelDifference) - 1;
                    ti.UseSubTileBitmapMask = false;
                }
                else if (zoom > ZoomIntervalConfig.BaseZoomLevel)
                {
                    // calculate the XY numbers of the parent base tile
                    int zoomLevelDifference = zoom - ZoomIntervalConfig.BaseZoomLevel;
                    ti.FromBaseTileX        = x >> zoomLevelDifference;
                    ti.FromBaseTileY        = y >> zoomLevelDifference;
                    ti.ToBaseTileX          = ti.FromBaseTileX;
                    ti.ToBaseTileY          = ti.FromBaseTileY;
                    ti.UseSubTileBitmapMask = true;

                    //calculate ti.SubTileBitmapMask
                    if (zoomLevelDifference == 1)
                    {
                        if (x % 2 == 0 && y % 2 == 0)
                        {
                            // upper left quadrant
                            ti.SubTileBitmapMask = 0xcc00;
                        }
                        else if (x % 2 == 1 && y % 2 == 0)
                        {
                            // upper right quadrant
                            ti.SubTileBitmapMask = 0x3300;
                        }
                        else if (x % 2 == 0 && y % 2 == 1)
                        {
                            // lower left quadrant
                            ti.SubTileBitmapMask = 0xcc;
                        }
                        else
                        {
                            // lower right quadrant
                            ti.SubTileBitmapMask = 0x33;
                        }
                    }
                    else
                    {
                        // calculate the XY numbers of the second level sub-tile
                        long subtileX = x >> (zoomLevelDifference - 2);
                        long subtileY = y >> (zoomLevelDifference - 2);

                        // calculate the XY numbers of the parent tile
                        long parentTileX = subtileX >> 1;
                        long parentTileY = subtileY >> 1;

                        // determine the correct bitmask for all 16 sub-tiles
                        if (parentTileX % 2 == 0 && parentTileY % 2 == 0)
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x8000;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x4000;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x800;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x400;
                            }
                        }
                        else if (parentTileX % 2 == 1 && parentTileY % 2 == 0)
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x2000;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x1000;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x200;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x100;
                            }
                        }
                        else if (parentTileX % 2 == 0 && parentTileY % 2 == 1)
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x80;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x40;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x8;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x4;
                            }
                        }
                        else
                        {
                            if (subtileX % 2 == 0 && subtileY % 2 == 0)
                            {
                                // upper left sub-tile
                                ti.SubTileBitmapMask = 0x20;
                            }
                            else if (subtileX % 2 == 1 && subtileY % 2 == 0)
                            {
                                // upper right sub-tile
                                ti.SubTileBitmapMask = 0x10;
                            }
                            else if (subtileX % 2 == 0 && subtileY % 2 == 1)
                            {
                                // lower left sub-tile
                                ti.SubTileBitmapMask = 0x2;
                            }
                            else
                            {
                                // lower right sub-tile
                                ti.SubTileBitmapMask = 0x1;
                            }
                        }
                    }
                }
                else
                {
                    // use the tile XY numbers of the requested tile
                    ti.FromBaseTileX        = x;
                    ti.FromBaseTileY        = y;
                    ti.ToBaseTileX          = ti.FromBaseTileX;
                    ti.ToBaseTileY          = ti.FromBaseTileY;
                    ti.UseSubTileBitmapMask = false;
                }

                ti.FromBlockX = Math.Max(ti.FromBaseTileX - MinX, 0);
                ti.FromBlockY = Math.Max(ti.FromBaseTileY - MinY, 0);
                ti.ToBlockX   = Math.Min(ti.ToBaseTileX - MinX, MaxX);
                ti.ToBlockY   = Math.Min(ti.ToBaseTileY - MinY, MaxY);

                ti.POIs = new List <POI>();
                ti.Ways = new List <Way>();
                for (long row = ti.FromBlockY; row <= ti.ToBlockY; row++)
                {
                    for (long column = ti.FromBlockX; column <= ti.ToBlockX; column++)
                    {
                        // calculate the actual block number of the needed block in the file
                        long blockNumber = (row * (MaxX - MinX + 1)) + column;
                        if (blockNumber >= _tileAbsOffsets.Length || _tileAbsOffsets[blockNumber] == 0 || _tileAbsOffsets[blockNumber] >= ZoomIntervalConfig.SubFileSize)
                        {
                            continue;
                        }

                        long blockSize;
                        if (blockNumber < _tileAbsOffsets.Length - 1)
                        {
                            blockSize = _tileAbsOffsets[blockNumber + 1] - _tileAbsOffsets[blockNumber];
                        }
                        else
                        {
                            blockSize = ZoomIntervalConfig.SubFileSize - _tileAbsOffsets[blockNumber] + 1;
                        }
                        if (blockSize < 1)
                        {
                            continue;
                        }

                        ti.TileDataBuffer = new byte[blockSize];
                        _mapFile.ReadBuffer(ti.TileDataBuffer, _tileAbsOffsets[blockNumber] + ZoomIntervalConfig.AbsStartPositionSubFile, (int)blockSize);
                        using (ti.TileDataBufferStream = new System.IO.MemoryStream(ti.TileDataBuffer))
                        {
                            // calculate the top-left coordinates of the underlying tile
                            ti.TileLatitudeDeg  = MapFile.GetLatitude(MinY + row, ZoomIntervalConfig.BaseZoomLevel);
                            ti.TileLongitudeDeg = MapFile.GetLongitude(MinX + column, ZoomIntervalConfig.BaseZoomLevel);
                            ti.TileLatitude     = (int)(ti.TileLatitudeDeg * 1000000);
                            ti.TileLongitude    = (int)(ti.TileLongitudeDeg * 1000000);

                            if (_mapFile.Header.DebugInformationPresent)
                            {
                                ti.TileDataBufferStream.Position = 32;
                            }

                            //get the zoom table
                            int rows = ZoomIntervalConfig.MaxZoomLevel - ZoomIntervalConfig.MinZoomLevel + 1;
                            ti.ZoomTable = new int[rows, 2];

                            int cumulatedNumberOfPois = 0;
                            int cumulatedNumberOfWays = 0;

                            for (int r = 0; r < rows; r++)
                            {
                                cumulatedNumberOfPois += (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                cumulatedNumberOfWays += (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);

                                ti.ZoomTable[r, 0] = cumulatedNumberOfPois;
                                ti.ZoomTable[r, 1] = cumulatedNumberOfWays;
                            }
                            ti.ZoomTableRow         = zoom - ZoomIntervalConfig.MinZoomLevel;
                            ti.PoisOnQueryZoomLevel = ti.ZoomTable[ti.ZoomTableRow, 0];
                            ti.WaysOnQueryZoomLevel = ti.ZoomTable[ti.ZoomTableRow, 1];

                            ti.FirstWayOffset  = MapFile.ReadVBEUint(ti.TileDataBufferStream);
                            ti.FirstWayOffset += ti.TileDataBufferStream.Position;

                            //get POIs
                            for (int p = 0; p < ti.PoisOnQueryZoomLevel; p++)
                            {
                                POI poi = new POI();

                                if (_mapFile.Header.DebugInformationPresent)
                                {
                                    ti.TileDataBufferStream.Position += 32;
                                }

                                //lat/lon
                                poi.Latitude  = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                poi.Longitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                //layer and tag ids
                                poi.TagIDs = new List <int>();
                                byte b = (byte)ti.TileDataBufferStream.ReadByte();
                                poi.Layer = b >> 4;
                                int tagCount = (b & 0x0F);
                                for (int t = 0; t < tagCount; t++)
                                {
                                    poi.TagIDs.Add((int)MapFile.ReadVBEUint(ti.TileDataBufferStream));
                                }

                                //flags
                                b = (byte)ti.TileDataBufferStream.ReadByte();
                                if ((b & 0x80) == 0x80)
                                {
                                    poi.Name = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    poi.Name = null;
                                }
                                if ((b & 0x40) == 0x40)
                                {
                                    poi.HouseNumber = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    poi.HouseNumber = null;
                                }
                                if ((b & 0x20) == 0x20)
                                {
                                    poi.Elevation = MapFile.ReadVBESint(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    poi.Elevation = null;
                                }

                                ti.POIs.Add(poi);
                            }

                            ti.TileDataBufferStream.Position = ti.FirstWayOffset;

                            //get ways
                            for (int w = 0; w < ti.WaysOnQueryZoomLevel; w++)
                            {
                                Way way = new Way();

                                if (_mapFile.Header.DebugInformationPresent)
                                {
                                    ti.TileDataBufferStream.Position += 32;
                                }

                                int wayDataSize   = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                int subTileBitmap = MapFile.ReadUInt16(ti.TileDataBufferStream);

                                if (ti.UseSubTileBitmapMask)
                                {
                                    // check if the way is inside the requested tile
                                    if ((ti.SubTileBitmapMask & subTileBitmap) == 0)
                                    {
                                        // skip the rest of the way and continue with the next way
                                        ti.TileDataBufferStream.Position += (wayDataSize - 2);
                                        continue;
                                    }
                                }

                                //layer and tags
                                way.TagIDs = new List <int>();
                                byte b = (byte)ti.TileDataBufferStream.ReadByte();
                                way.Layer = b >> 4;
                                int tagCount = (b & 0x0F);
                                for (int t = 0; t < tagCount; t++)
                                {
                                    way.TagIDs.Add((int)MapFile.ReadVBEUint(ti.TileDataBufferStream));
                                }

                                //feature bytes
                                b = (byte)ti.TileDataBufferStream.ReadByte();
                                if ((b & 0x80) == 0x80)
                                {
                                    way.Name = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.Name = null;
                                }
                                if ((b & 0x40) == 0x40)
                                {
                                    way.HouseNumber = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.HouseNumber = null;
                                }
                                if ((b & 0x20) == 0x20)
                                {
                                    way.Reference = MapFile.ReadUTF8EncodedString(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.Reference = null;
                                }
                                if ((b & 0x10) == 0x10)
                                {
                                    way.LabelLatitude  = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                    way.LabelLongitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    way.LabelLatitude  = null;
                                    way.LabelLongitude = null;
                                }

                                int numberOfBlocks;
                                if ((b & 0x08) == 0x08)
                                {
                                    numberOfBlocks = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                }
                                else
                                {
                                    numberOfBlocks = 1;
                                }

                                bool doubleEncoding = ((b & 0x04) == 0x04);
                                way.WayDataBlocks = new List <Way.WayData>();
                                for (int wb = 0; wb < numberOfBlocks; wb++)
                                {
                                    //read: way data
                                    Way.WayData wd = new Way.WayData();

                                    int numberOfWayCoordBlocks = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                    wd.DataBlock = new List <Way.WayCoordinateBlock>();
                                    for (int wcd = 0; wcd < numberOfWayCoordBlocks; wcd++)
                                    {
                                        //read way coordinate block
                                        Way.WayCoordinateBlock coordBlock = new Way.WayCoordinateBlock();
                                        coordBlock.CoordBlock = new List <Way.WayCoordinate>();

                                        int nodesCount = (int)MapFile.ReadVBEUint(ti.TileDataBufferStream);
                                        //Way.WayCoordinate diffwc = wc;
                                        if (doubleEncoding)
                                        {
                                            // get the first way node latitude single-delta offset (VBE-S)
                                            int wayNodeLatitude = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                            // get the first way node longitude single-delta offset (VBE-S)
                                            int wayNodeLongitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                            // store the first way node
                                            Way.WayCoordinate wc = new Way.WayCoordinate();
                                            wc.Latitude  = wayNodeLatitude;
                                            wc.Longitude = wayNodeLongitude;
                                            coordBlock.CoordBlock.Add(wc);

                                            int previousSingleDeltaLatitude  = 0;
                                            int previousSingleDeltaLongitude = 0;

                                            for (int n = 1; n < nodesCount; n++)
                                            {
                                                // get the way node latitude double-delta offset (VBE-S)
                                                int doubleDeltaLatitude = MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                // get the way node longitude double-delta offset (VBE-S)
                                                int doubleDeltaLongitude = MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                int singleDeltaLatitude  = doubleDeltaLatitude + previousSingleDeltaLatitude;
                                                int singleDeltaLongitude = doubleDeltaLongitude + previousSingleDeltaLongitude;

                                                wayNodeLatitude  = wayNodeLatitude + singleDeltaLatitude;
                                                wayNodeLongitude = wayNodeLongitude + singleDeltaLongitude;

                                                Way.WayCoordinate wcNext = new Way.WayCoordinate();
                                                wcNext.Latitude  = wayNodeLatitude;
                                                wcNext.Longitude = wayNodeLongitude;
                                                coordBlock.CoordBlock.Add(wcNext);

                                                previousSingleDeltaLatitude  = singleDeltaLatitude;
                                                previousSingleDeltaLongitude = singleDeltaLongitude;
                                            }
                                        }
                                        else
                                        {
                                            // get the first way node latitude single-delta offset (VBE-S)
                                            int wayNodeLatitude = ti.TileLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);
                                            // get the first way node longitude single-delta offset (VBE-S)
                                            int wayNodeLongitude = ti.TileLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                            // store the first way node
                                            Way.WayCoordinate wc = new Way.WayCoordinate();
                                            wc.Latitude  = wayNodeLatitude;
                                            wc.Longitude = wayNodeLongitude;
                                            coordBlock.CoordBlock.Add(wc);

                                            for (int n = 1; n < nodesCount; n++)
                                            {
                                                // get the way node latitude offset (VBE-S)
                                                wayNodeLatitude = wayNodeLatitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                // get the way node longitude offset (VBE-S)
                                                wayNodeLongitude = wayNodeLongitude + MapFile.ReadVBESint(ti.TileDataBufferStream);

                                                Way.WayCoordinate wcNext = new Way.WayCoordinate();
                                                wcNext.Latitude  = wayNodeLatitude;
                                                wcNext.Longitude = wayNodeLongitude;
                                                coordBlock.CoordBlock.Add(wcNext);
                                            }
                                        }

                                        wd.DataBlock.Add(coordBlock);
                                    }

                                    way.WayDataBlocks.Add(wd);
                                }

                                ti.Ways.Add(way);
                            }
                        }
                    }
                }
                ti.TileDataBuffer = null; //memory can be released
            }
            catch
            {
                ti = null;
            }
            return(ti);
        }