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 { } } }
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); }
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); }
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); }
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); } } } } } }
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); } } }
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)); }
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); } } } } } }
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); }
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; }
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 { } } }
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; }
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 { } } }
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); } } }
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); }
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; }