internal virtual void AddTileInProgress(Tile tileInProgress) { lock (this) { tilesInProgress.Add(tileInProgress); } }
private void DrawTileCoordinates(TilePosition tilePosition, ICanvas canvas) { int x = (int)(tilePosition.Point.X + 8 * displayModel.ScaleFactor); int y = (int)(tilePosition.Point.Y + 24 * displayModel.ScaleFactor); Tile tile = tilePosition.Tile; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("X: "); stringBuilder.Append(tile.TileX); string text = stringBuilder.ToString(); canvas.DrawText(text, x, y, this.paintBack); canvas.DrawText(text, x, y, this.paintFront); stringBuilder.Length = 0; stringBuilder.Append("Y: "); stringBuilder.Append(tile.TileY); text = stringBuilder.ToString(); canvas.DrawText(text, x, (int)(y + 24 * displayModel.ScaleFactor), this.paintBack); canvas.DrawText(text, x, (int)(y + 24 * displayModel.ScaleFactor), this.paintFront); stringBuilder.Length = 0; stringBuilder.Append("Z: "); stringBuilder.Append(tile.ZoomLevel); text = stringBuilder.ToString(); canvas.DrawText(text, x, (int)(y + 48 * displayModel.ScaleFactor), this.paintBack); canvas.DrawText(text, x, (int)(y + 48 * displayModel.ScaleFactor), this.paintFront); }
public virtual void ExecuteQueryTest() { MapFile mapFile = new MapFile(MAP_FILE); MapFileInfo mapFileInfo = mapFile.MapFileInfo; Assert.True(mapFileInfo.DebugFile); for (sbyte zoomLevel = ZOOM_LEVEL_MIN; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { int tileX = MercatorProjection.LongitudeToTileX(0.04, zoomLevel); int tileY = MercatorProjection.LatitudeToTileY(0.04, zoomLevel); Tile tile = new Tile(tileX, tileY, zoomLevel, 256); MapReadResult mapReadResult = mapFile.ReadMapData(tile); Assert.AreEqual(1, mapReadResult.PointOfInterests.Count); Assert.AreEqual(1, mapReadResult.Ways.Count); CheckPointOfInterest(mapReadResult.PointOfInterests[0]); CheckWay(mapReadResult.Ways[0]); } mapFile.Close(); }
internal virtual void RemoveTileInProgress(Tile tile) { if (this.tileDependencies != null) { this.tileDependencies.RemoveTileInProgress(tile); } }
/// <summary> /// Returns if a tile is in the current tile set and no data is stored for this tile. </summary> /// <param name="tile"> the tile </param> /// <returns> true if the tile is in the current tile set, but no data is stored for it. </returns> public virtual bool requiresTile(Tile tile) { lock (this) { return(this.lastVisibleTileSet.Contains(tile) && !this.ContainsKey(tile)); } }
internal static void RunTest(MapFile mapFile) { int tileX = MercatorProjection.LongitudeToTileX(0, ZOOM_LEVEL); int tileY = MercatorProjection.LatitudeToTileY(0, ZOOM_LEVEL); Tile tile = new Tile(tileX, tileY, ZOOM_LEVEL, 256); MapReadResult mapReadResult = mapFile.ReadMapData(tile); mapFile.Close(); Assert.AreEqual(mapReadResult.PointOfInterests.Count, 0); Assert.AreEqual(1, mapReadResult.Ways.Count); LatLong latLong1 = new LatLong(0.0, 0.0, true); LatLong latLong2 = new LatLong(0.0, 0.1, true); LatLong latLong3 = new LatLong(-0.1, 0.1, true); LatLong latLong4 = new LatLong(-0.1, 0.0, true); LatLong[][] latLongsExpected = new LatLong[][] { new LatLong[] { latLong1, latLong2, latLong3, latLong4, latLong1 } }; Way way = mapReadResult.Ways[0]; // TODO: Was ArrayEquals() Assert.AreEqual(latLongsExpected, way.LatLongs); }
internal virtual bool IsTileInProgress(Tile tile) { lock (this) { return(tilesInProgress.Contains(tile)); } }
private void DrawParentTileBitmap(ICanvas canvas, Point point, Tile tile) { Tile cachedParentTile = GetCachedParentTile(tile, 4); if (cachedParentTile != null) { IBitmap bitmap = this.tileCache.GetImmediately(CreateJob(cachedParentTile)); if (bitmap != null) { int tileSize = this.displayModel.TileSize; long translateX = tile.GetShiftX(cachedParentTile) * tileSize; long translateY = tile.GetShiftY(cachedParentTile) * tileSize; sbyte zoomLevelDiff = (sbyte)(tile.ZoomLevel - cachedParentTile.ZoomLevel); float scaleFactor = (float)Math.Pow(2, zoomLevelDiff); int x = (int)Math.Round(point.X); int y = (int)Math.Round(point.Y); this.matrix.Reset(); this.matrix.Translate(x - translateX, y - translateY); this.matrix.Scale(scaleFactor, scaleFactor); canvas.SetClip(x, y, this.displayModel.TileSize, this.displayModel.TileSize); canvas.DrawBitmap(bitmap, this.matrix); canvas.ResetClip(); bitmap.DecrementRefCount(); } } }
/// <summary> /// Cache maintenance operation to remove data for a tile from the cache. This should be excuted /// if a tile is removed from the TileCache and will be drawn again. </summary> /// <param name="from"> </param> internal virtual void RemoveTileData(Tile from, Tile to) { if (overlapData.ContainsKey(from)) { overlapData[from].Remove(to); } }
internal virtual void RemoveTileInProgress(Tile tileFinished) { lock (this) { tilesInProgress.Remove(tileFinished); } }
public override void Draw(BoundingBox boundingBox, sbyte zoomLevel, ICanvas canvas, Point topLeftPoint) { IList <TilePosition> tilePositions = LayerUtil.GetTilePositions(boundingBox, zoomLevel, topLeftPoint, this.displayModel.TileSize); // In a rotation situation it is possible that drawParentTileBitmap sets the // clipping bounds to portrait, while the device is just being rotated into // landscape: the result is a partially painted screen that only goes away // after zooming (which has the effect of resetting the clip bounds if drawParentTileBitmap // is called again). // Always resetting the clip bounds here seems to avoid the problem, // I assume that this is a pretty cheap operation, otherwise it would be better // to hook this into the onConfigurationChanged call chain. canvas.ResetClip(); if (!isTransparent) { canvas.FillColor(this.displayModel.BackgroundColor); } ISet <Job> jobs = new HashSet <Job>(); foreach (TilePosition tilePosition in tilePositions) { jobs.Add(CreateJob(tilePosition.Tile)); } this.tileCache.WorkingSet = jobs; for (int i = tilePositions.Count - 1; i >= 0; --i) { TilePosition tilePosition = tilePositions[i]; Point point = tilePosition.Point; Tile tile = tilePosition.Tile; T job = CreateJob(tile); ITileBitmap bitmap = this.tileCache.GetImmediately(job); if (bitmap == null) { if (this.hasJobQueue && !this.tileCache.ContainsKey(job)) { this.jobQueue.Add(job); } DrawParentTileBitmap(canvas, point, tile); } else { if (IsTileStale(tile, bitmap) && this.hasJobQueue && !this.tileCache.ContainsKey(job)) { this.jobQueue.Add(job); } RetrieveLabelsOnly(job); canvas.DrawBitmap(bitmap, (int)Math.Round(point.X), (int)Math.Round(point.Y)); bitmap.DecrementRefCount(); } } if (this.hasJobQueue) { this.jobQueue.NotifyWorkers(); } }
/// <summary> /// Stores a list of MapElements against a tile. /// </summary> /// <param name="tile"> tile on which the mapItems reside. </param> /// <param name="mapItems"> the map elements. </param> public virtual void StoreMapItems(Tile tile, ICollection <MapElementContainer> mapItems) { lock (this) { this.Add(tile, LayerUtil.CollisionFreeOrdered(mapItems)); this.version += 1; } }
/// <summary> /// Retrieves the overlap data from the neighbouring tiles </summary> /// <param name="from"> the origin tile </param> /// <param name="to"> the tile the label clashesWith to </param> /// <returns> a List of the elements </returns> internal virtual ISet <MapElementContainer> GetOverlappingElements(Tile from, Tile to) { if (overlapData.ContainsKey(from) && overlapData[from].ContainsKey(to)) { return(overlapData[from][to]); } return(new HashSet <MapElementContainer>()); }
/// <summary> /// Whether the tile is stale and should be refreshed. /// <para> /// This method is called from <seealso cref="#draw(BoundingBox, byte, Canvas, Point)"/> to determine whether the tile needs to /// be refreshed. /// </para> /// <para> /// A tile is considered stale if one or more of the following two conditions apply: /// <ul> /// <li>The {@code bitmap}'s <seealso cref="MapsforgeSharp.Core.Graphics.ITileBitmap#isExpired()"/> method returns {@code True}.</li> /// <li>The layer has a time-to-live (TTL) set (<seealso cref="#getCacheTimeToLive()"/> returns a nonzero value) and the sum of /// the {@code bitmap}'s <seealso cref="MapsforgeSharp.Core.Graphics.ITileBitmap#getTimestamp()"/> and TTL is less than current /// time (as returned by <seealso cref="java.lang.System#currentTimeMillis()"/>).</li> /// </ul> /// </para> /// <para> /// When a tile has become stale, the layer will first display the tile referenced by {@code bitmap} and attempt to /// obtain a fresh copy in the background. When a fresh copy becomes available, the layer will replace it and update /// the cache. If a fresh copy cannot be obtained (e.g. because the tile is obtained from an online source which /// cannot be reached), the stale tile will continue to be used until another /// {@code #draw(BoundingBox, byte, Canvas, Point)} operation requests it again. /// /// </para> /// </summary> /// <param name="tile"> /// A tile. This parameter is not used for a {@code TileDownloadLayer} and can be null. </param> /// <param name="bitmap"> /// The bitmap for {@code tile} currently held in the layer's cache. </param> protected internal override bool IsTileStale(Tile tile, ITileBitmap bitmap) { if (bitmap.Expired) { return(true); } return(cacheTimeToLive != 0 && ((bitmap.Timestamp + cacheTimeToLive) < DateTimeHelperClass.CurrentUnixTimeMillis())); }
internal PolylineContainer(Way way, Tile tile) { this.coordinatesAbsolute = null; this.coordinatesRelativeToTile = null; this.tags = way.Tags; this.tile = tile; layer = way.Layer; this.way = way; this.isClosedWay_Renamed = IsClosedWay(way.LatLongs[0]); }
public Job(Tile tile, bool hasAlpha) { if (tile == null) { throw new System.ArgumentException("tile must not be null"); } this.tile = tile; this.hasAlpha = hasAlpha; this.key = ComposeKey(this.tile.ZoomLevel, this.tile.TileX, this.tile.TileY); }
internal PolylineContainer(Point[] coordinates, Tile tile, IList <Tag> tags) { this.coordinatesAbsolute = new Point[1][]; this.coordinatesRelativeToTile = null; this.coordinatesAbsolute[0] = new Point[coordinates.Length]; Array.Copy(coordinates, 0, coordinatesAbsolute[0], 0, coordinates.Length); this.tags = tags; this.tile = tile; this.layer = 0; isClosedWay_Renamed = coordinates[0].Equals(coordinates[coordinates.Length - 1]); }
/// <summary> /// stores an MapElementContainer that clashesWith from one tile (the one being drawn) to /// another (which must not have been drawn before). </summary> /// <param name="from"> origin tile </param> /// <param name="to"> tile the label clashesWith to </param> /// <param name="element"> the MapElementContainer in question </param> internal virtual void AddOverlappingElement(Tile from, Tile to, MapElementContainer element) { if (!overlapData.ContainsKey(from)) { overlapData[from] = new Dictionary <Tile, ISet <MapElementContainer> >(); } if (!overlapData[from].ContainsKey(to)) { overlapData[from][to] = new HashSet <MapElementContainer>(); } overlapData[from][to].Add(element); }
internal virtual void DrawMapElements(ISet <MapElementContainer> elements, Tile tile) { // we have a set of all map elements (needed so we do not draw elements twice), // but we need to draw in priority order as we now allow overlaps. So we // convert into list, then sort, then draw. // draw elements in order of priority: lower priority first, so more important // elements will be drawn on top (in case of display=true) items. var elementsAsList = from element in elements orderby element.Priority ascending select element; foreach (MapElementContainer element in elementsAsList) { element.Draw(canvas, tile.Origin, this.symbolMatrix); } }
public override Uri GetTileUrl(Tile tile) { StringBuilder stringBuilder = new StringBuilder(32); stringBuilder.Append(baseUrl); stringBuilder.Append(tile.ZoomLevel); stringBuilder.Append('/'); stringBuilder.Append(tile.TileX); stringBuilder.Append('/'); stringBuilder.Append(tile.TileY); stringBuilder.Append('.').Append(extension); return(new Uri(string.Format("{0}://{1}:{2}{3}", this.protocol, HostName, this.port, stringBuilder.ToString()))); }
public virtual void LatitudeToTileYTest() { for (sbyte zoomLevel = ZOOM_LEVEL_MIN; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { long tileY = MercatorProjection.LatitudeToTileY(MercatorProjection.LATITUDE_MAX, zoomLevel); Assert.AreEqual(0, tileY); tileY = MercatorProjection.LatitudeToTileY(MercatorProjection.LATITUDE_MAX, MercatorProjection.ZoomLevelToScaleFactor(zoomLevel)); Assert.AreEqual(0, tileY); tileY = MercatorProjection.LatitudeToTileY(MercatorProjection.LATITUDE_MIN, zoomLevel); Assert.AreEqual(Tile.GetMaxTileNumber(zoomLevel), tileY); tileY = MercatorProjection.LatitudeToTileY(MercatorProjection.LATITUDE_MIN, MercatorProjection.ZoomLevelToScaleFactor(zoomLevel)); Assert.AreEqual(Tile.GetMaxTileNumber(zoomLevel), tileY); } }
public virtual void LongitudeToTileXTest() { for (sbyte zoomLevel = ZOOM_LEVEL_MIN; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { long tileX = MercatorProjection.LongitudeToTileX(LatLongUtils.LONGITUDE_MIN, zoomLevel); Assert.AreEqual(0, tileX); tileX = MercatorProjection.LongitudeToTileX(LatLongUtils.LONGITUDE_MIN, MercatorProjection.ZoomLevelToScaleFactor(zoomLevel)); Assert.AreEqual(0, tileX); tileX = MercatorProjection.LongitudeToTileX(LatLongUtils.LONGITUDE_MAX, zoomLevel); Assert.AreEqual(Tile.GetMaxTileNumber(zoomLevel), tileX); tileX = MercatorProjection.LongitudeToTileX(LatLongUtils.LONGITUDE_MAX, MercatorProjection.ZoomLevelToScaleFactor(zoomLevel)); Assert.AreEqual(Tile.GetMaxTileNumber(zoomLevel), tileX); } }
public virtual void ExecuteQueryTest() { MapFile mapFile = new MapFile(MAP_FILE); for (sbyte zoomLevel = 0; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { int tileX = MercatorProjection.LongitudeToTileX(1, zoomLevel); int tileY = MercatorProjection.LatitudeToTileY(1, zoomLevel); Tile tile = new Tile(tileX, tileY, zoomLevel, 256); MapReadResult mapReadResult = mapFile.ReadMapData(tile); Assert.AreEqual(0, mapReadResult.PointOfInterests.Count); Assert.AreEqual(0, mapReadResult.Ways.Count); } mapFile.Close(); }
public RendererJob(Tile tile, MapDataStore mapFile, RenderThemeFuture renderThemeFuture, DisplayModel displayModel, float textScale, bool isTransparent, bool labelsOnly) : base(tile, isTransparent) { if (mapFile == null) { throw new System.ArgumentException("mapFile must not be null"); } else if (textScale <= 0 || float.IsNaN(textScale)) { throw new System.ArgumentException("invalid textScale: " + textScale); } this.labelsOnly = labelsOnly; this.displayModel = displayModel; this.mapDataStore = mapFile; this.renderThemeFuture = renderThemeFuture; this.textScale = textScale; this.hashCodeValue = CalculateHashCode(); }
/// <returns> the first parent object of the given object whose tileCacheBitmap is cached (may be null). </returns> private Tile GetCachedParentTile(Tile tile, int level) { if (level == 0) { return(null); } Tile parentTile = tile.Parent; if (parentTile == null) { return(null); } else if (this.tileCache.ContainsKey(CreateJob(parentTile))) { return(parentTile); } return(GetCachedParentTile(parentTile, level - 1)); }
public override Uri GetTileUrl(Tile tile) { return(new Uri(string.Format("{0}://{1}:{2}{3}", PROTOCOL, HostName, this.port, "/cycle/" + tile.ZoomLevel + '/' + tile.TileX + '/' + tile.TileY + ".png"))); }
public DownloadJob(Tile tile, TileSource tileSource) : base(tile, tileSource.HasAlpha()) { this.tileSource = tileSource; }
private ISet <MapElementContainer> ProcessLabels(RenderContext renderContext) { // if we are drawing the labels per tile, we need to establish which tile-overlapping // elements need to be drawn. ISet <MapElementContainer> labelsToDraw = new HashSet <MapElementContainer>(); lock (tileDependencies) { // first we need to get the labels from the adjacent tiles if they have already been drawn // as those overlapping items must also be drawn on the current tile. They must be drawn regardless // of priority clashes as a part of them has alread been drawn. ISet <Tile> neighbours = renderContext.rendererJob.tile.Neighbours; ISet <MapElementContainer> undrawableElements = new HashSet <MapElementContainer>(); tileDependencies.AddTileInProgress(renderContext.rendererJob.tile); for (var i = neighbours.Count - 1; i >= 0; i--) { Tile neighbour = neighbours.ElementAt(i); if (tileDependencies.IsTileInProgress(neighbour) || tileCache.ContainsKey(renderContext.rendererJob.OtherTile(neighbour))) { // if a tile has already been drawn, the elements drawn that overlap onto the // current tile should be in the tile dependencies, we add them to the labels that // need to be drawn onto this tile. For the multi-threaded renderer we also need to take // those tiles into account that are not yet in the TileCache: this is taken care of by the // set of tilesInProgress inside the TileDependencies. labelsToDraw.UnionWith(tileDependencies.GetOverlappingElements(neighbour, renderContext.rendererJob.tile)); // but we need to remove the labels for this tile that overlap onto a tile that has been drawn foreach (MapElementContainer current in renderContext.labels) { if (current.Intersects(neighbour.BoundaryAbsolute)) { undrawableElements.Add(current); } } // since we already have the data from that tile, we do not need to get the data for // it, so remove it from the neighbours list. neighbours.Remove(neighbour); } else { tileDependencies.RemoveTileData(neighbour); } } // now we remove the elements that overlap onto a drawn tile from the list of labels // for this tile foreach (var element in undrawableElements) { renderContext.labels.Remove(element); } // at this point we have two lists: one is the list of labels that must be drawn because // they already overlap from other tiles. The second one is currentLabels that contains // the elements on this tile that do not overlap onto a drawn tile. Now we sort this list and // remove those elements that clash in this list already. IList <MapElementContainer> currentElementsOrdered = LayerUtil.CollisionFreeOrdered(renderContext.labels); // now we go through this list, ordered by priority, to see which can be drawn without clashing. IEnumerator <MapElementContainer> currentMapElementsIterator = currentElementsOrdered.GetEnumerator(); while (currentMapElementsIterator.MoveNext()) { MapElementContainer current = currentMapElementsIterator.Current; foreach (MapElementContainer label in labelsToDraw) { if (label.ClashesWith(current)) { break; } } } labelsToDraw.UnionWith(currentElementsOrdered); // update dependencies, add to the dependencies list all the elements that overlap to the // neighbouring tiles, first clearing out the cache for this relation. foreach (Tile tile in neighbours) { tileDependencies.RemoveTileData(renderContext.rendererJob.tile, tile); foreach (MapElementContainer element in labelsToDraw) { if (element.Intersects(tile.BoundaryAbsolute)) { tileDependencies.AddOverlappingElement(renderContext.rendererJob.tile, tile, element); } } } } return(labelsToDraw); }
internal virtual void MatchWay(RenderCallback renderCallback, PolylineContainer way, Tile tile, Closed closed, IList <RenderInstruction> matchingList, RenderContext renderContext) { if (MatchesWay(way.Tags, tile.ZoomLevel, closed)) { for (int i = 0, n = this.renderInstructions.Count; i < n; ++i) { this.renderInstructions[i].RenderWay(renderCallback, renderContext, way); matchingList.Add(this.renderInstructions[i]); } for (int i = 0, n = this.subRules.Count; i < n; ++i) { this.subRules[i].MatchWay(renderCallback, way, tile, closed, matchingList, renderContext); } } }
/// <summary> /// Just a way of generating a hash key for a tile if only the RendererJob is known. </summary> /// <param name="tile"> the tile that changes </param> /// <returns> a RendererJob based on the current one, only tile changes </returns> public virtual RendererJob OtherTile(Tile tile) { return(new RendererJob(tile, this.mapDataStore, this.renderThemeFuture, this.displayModel, this.textScale, this.hasAlpha, this.labelsOnly)); }