/// <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; } }
public override void Draw(BoundingBox boundingBox, sbyte zoomLevel, ICanvas canvas, Point topLeftPoint) { ISet <Tile> currentTileSet = LayerUtil.GetTiles(boundingBox, zoomLevel, displayModel.TileSize); if (!currentTileSet.Equals(lastTileSet) || lastLabelStoreVersion != labelStore.Version) { // only need to get new data set if either set of tiles changed or the label store lastTileSet = currentTileSet; lastLabelStoreVersion = labelStore.Version; IList <MapElementContainer> visibleItems = this.labelStore.GetVisibleItems(currentTileSet); // TODO this is code duplicated from CanvasRasterer::drawMapElements, should be factored out // what LayerUtil.collisionFreeOrdered gave us is a list where highest priority comes first, // so we need to reverse that in order to // draw elements in order of priority: lower priority first, so more important // elements will be drawn on top (in case of display=true) items. elementsToDraw = from element in LayerUtil.CollisionFreeOrdered(visibleItems) orderby element.Priority ascending select element; } foreach (MapElementContainer item in elementsToDraw) { item.Draw(canvas, topLeftPoint, this.matrix); } }
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. ICollection <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); }