/// <summary> /// Generates all the tiles at the level specified for a given region of the world. /// </summary> /// <param name="level"> /// Base level of zoom. /// </param> /// <param name="boundary"> /// Bounding coordinates of the region. /// </param> /// <remarks> /// This API should be used only for a sparse region of the world. /// The overhead involved in computing the relevant tiles is negligible for a sparse region. /// </remarks> public void BuildLevel(int level, Boundary boundary) { if (boundary == null) { throw new ArgumentNullException("boundary"); } Trace.TraceInformation("{0}: Building image at level {1}..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture), level); CurrentLevel = level; if (this.tileCreator.ProjectionType == ProjectionTypes.Toast) { this.toastProjectionCoordinates = ToastHelper.ComputeTileCoordinates(boundary, level); Parallel.ForEach( this.toastProjectionCoordinates[level], this.ParallelOptions, tile => { this.tileCreator.Create(level, tile.X, tile.Y); Interlocked.Increment(ref this.tilesProcessed); this.ParallelOptions.CancellationToken.ThrowIfCancellationRequested(); }); } else { int tileXMin = Helper.GetMercatorXTileFromLongitude(boundary.Left, level); int tileXMax = Helper.GetMercatorXTileFromLongitude(boundary.Right, level); int tileYMin = Helper.GetMercatorYTileFromLatitude(boundary.Bottom, level); int tileYMax = Helper.GetMercatorYTileFromLatitude(boundary.Top, level); // If both xmin(ymin) and xmax(ymax) are equal, // the loop should run atleast for ONE time, Hence incrementing the Xmax(Ymax) by 1 tileXMax = (tileXMin == tileXMax) ? tileXMax + 1 : tileXMax; tileYMax = (tileYMin == tileYMax) ? tileYMax + 1 : tileYMax; tileXMax = (int)Math.Min(tileXMax + 1, Math.Pow(2, level)); tileYMax = (int)Math.Min(tileYMax + 1, Math.Pow(2, level)); Parallel.For( tileYMin, tileYMax, this.ParallelOptions, y => { for (int x = tileXMin; x < tileXMax; x++) { this.tileCreator.Create(level, x, y); Interlocked.Increment(ref this.tilesProcessed); this.ParallelOptions.CancellationToken.ThrowIfCancellationRequested(); } }); } }
/// <summary> /// Fills up the pyramid of tiles above the specified level. /// </summary> /// <param name="level"> /// Base level of zoom. /// </param> /// <param name="boundary"> /// Bounding coordinates of the region. /// </param> public void BuildParentLevels(int level, Boundary boundary) { if (boundary == null) { throw new ArgumentNullException("boundary"); } if (this.tileCreator.ProjectionType == ProjectionTypes.Toast) { this.toastProjectionCoordinates = ToastHelper.ComputeTileCoordinates(boundary, level); foreach (int k in Enumerable.Range(1, level).Select(i => level - i)) { Trace.TraceInformation("{0}: Filling up pyramid at level {1}..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture), k); CurrentLevel = k; Parallel.ForEach( this.toastProjectionCoordinates[k], this.ParallelOptions, tile => { this.tileCreator.CreateParent(k, tile.X, tile.Y); Interlocked.Increment(ref this.tilesProcessed); this.ParallelOptions.CancellationToken.ThrowIfCancellationRequested(); }); } } else { int tileXMin, tileXMax, tileYMin, tileYMax; foreach (int k in Enumerable.Range(1, level).Select(i => level - i)) { CurrentLevel = k; tileXMin = Helper.GetMercatorXTileFromLongitude(boundary.Left, k); tileXMax = Helper.GetMercatorXTileFromLongitude(boundary.Right, k); tileYMin = Helper.GetMercatorYTileFromLatitude(boundary.Bottom, k); tileYMax = Helper.GetMercatorYTileFromLatitude(boundary.Top, k); BuildParentLevels(k, tileXMin, tileXMax, tileYMin, tileYMax); } } }