Beispiel #1
0
        public WtmlCollection(string name, string thumbnailUrl, string textureTilePath, int numberOfLevels, ProjectionTypes type, Boundary inputBoundary)
        {
            this.Name = name;
            this.PlaceName = name;
            this.FolderName = name;
            this.TextureTilePath = textureTilePath;
            this.NumberOfLevels = numberOfLevels;
            this.ProjectionType = type;
            this.ThumbnailUrl = thumbnailUrl;

            // Assign default values.
            this.BaseDegreesPerTile = type == ProjectionTypes.Toast ? 90 : 360;
            this.BandPass = BandPasses.Visible;
            this.DataSetType = DataSetTypes.Earth;
            this.DemTilePath = string.Empty;
            this.FileType = ".png";
            this.QuadTreeMap = string.Empty;

            if (inputBoundary != null)
            {
                // Calculate average latitude and longitude.
                this.Latitude = (inputBoundary.Bottom + inputBoundary.Top) / 2;
                this.Longitude = (inputBoundary.Right + inputBoundary.Left) / 2;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Compute tile coordinates for a specified level. Computation is done by using tiles from the previous level.
        /// </summary>
        /// <param name="tiles">List of tiles already computed for previous levels.</param>
        /// <param name="preferredRegion">Region of interest.</param>
        /// <param name="level">Current level for which the tile coorinates has to be computed.</param>
        private static Dictionary<int, List<Tile>> ComputeTiles(Dictionary<int, List<Tile>> tiles, Boundary preferredRegion, int level)
        {
            if (level == 0)
            {
                return tiles;
            }

            List<Tile> points = tiles[level - 1];
            tiles.Add(level, new List<Tile>());

            int xmin, xmax, ymin, ymax;

            foreach (Tile point in points)
            {
                xmin = (int)point.X * 2;
                xmax = xmin + 1;
                ymin = (int)point.Y * 2;
                ymax = ymin + 1;

                for (int y = ymin; y <= ymax; y++)
                {
                    for (int x = xmin; x <= xmax; x++)
                    {
                        if (ToastHelper.IsDesiredTile(preferredRegion, level, x, y))
                        {
                            tiles[level].Add(new Tile(x, y));
                        }
                    }
                }
            }

            return tiles;
        }
Beispiel #3
0
        public static Dictionary<int, List<Tile>> ComputeTileCoordinates(Boundary preferredRegion, int maxLevel)
        {
            var tiles = new Dictionary<int, List<Tile>>();
            tiles.Add(0, new List<Tile> { new Tile(0, 0) });

            for (int level = 1; level <= maxLevel; level++)
            {
                tiles = ComputeTiles(tiles, preferredRegion, level);
            }

            return tiles;
        }
Beispiel #4
0
        /// <summary>
        /// Compute the maximum level of detail that this image supports.
        /// </summary>
        /// <param name="imageHeight">Image height (in Pixels).</param>
        /// <param name="imageWidth">Image width (in Pixels).</param>
        /// <param name="inputBoundary">Input boundary.</param>
        /// <returns>Max level for the input image</returns>
        public static int CalculateMaximumLevel(long imageHeight, long imageWidth, Boundary inputBoundary)
        {
            if (inputBoundary == null)
            {
                throw new ArgumentNullException("inputBoundary");
            }

            // Approach:
            //   1. Based on the input coordinates, calculate how much pixel represent each latitude of the given input image.
            //   2. Then image height for the whole world is (Pixels Representing an latitude) * 180.
            //   3. Once we have the total image height, then we can calculate the Number of levels as
            ////      “MaxLevel = Math.Ceiling(Math.Log((image height for the whole world) / 256 ) / Math.Log(2.0))”

            double actualImageHeight = 180 * (imageHeight / (inputBoundary.Bottom - inputBoundary.Top));
            double actualImageWidth = 360 * (imageWidth / (inputBoundary.Right - inputBoundary.Left));

            // If the image height is less than 256 , max level is 0.
            int maxLevelHeight = (actualImageHeight >= 256) ? (int)Math.Ceiling(Math.Log(actualImageHeight / Constants.TileSize) / Math.Log(2.0)) : 0;
            int maxLevelWidth = (actualImageWidth >= 256) ? (int)Math.Ceiling(Math.Log(actualImageWidth / Constants.TileSize) / Math.Log(2.0)) : 0;

            return (maxLevelHeight > maxLevelWidth) ? maxLevelHeight : maxLevelWidth;
        }
        /// <summary>
        /// Initializes a new instance of the EquirectangularGridMap class.
        /// </summary>
        /// <param name="inputGrid">
        /// Input grid.
        /// </param>
        /// <param name="boundary">
        /// Input boundary co-ordinates
        /// </param>
        public EquirectangularGridMap(IGrid inputGrid, Boundary boundary)
        {
            if (inputGrid == null)
            {
                throw new ArgumentNullException("inputGrid");
            }

            if (boundary == null)
            {
                throw new ArgumentNullException("boundary");
            }

            longitudeDelta = boundary.Right - boundary.Left;
            if (longitudeDelta > 360.0)
            {
                throw new ArgumentException("Longitude range must be less than 360 degrees.", "boundary");
            }

            if (longitudeDelta <= 0.0)
            {
                throw new ArgumentException("Longitudes must be increasing from left to right.", "boundary");
            }

            latitudeDelta = boundary.Top - boundary.Bottom;
            if (latitudeDelta >= 0.0)
            {
                throw new ArgumentException("Latitudes must be increasing from top to bottom.", "boundary");
            }

            if (latitudeDelta < -180.0)
            {
                throw new ArgumentException("Latitude range must be less than 180 degrees.", "boundary");
            }

            this.minimumLongitude = boundary.Left;
            this.maximumLatitude = boundary.Bottom;
            this.InputGrid = inputGrid;
            this.InputBoundary = boundary;
        }
Beispiel #6
0
        /// <summary>
        /// Processes the input equirectangular dataset.
        /// </summary>
        /// <param name="inputGrid">
        /// Input image path.
        /// </param>
        /// <param name="outputDir">
        /// Output directory where pyramid is generated.
        /// </param>
        /// <param name="projection">
        /// Projection type.
        /// </param>
        private static void ProcessEquirectangularGrid(string inputGrid, string outputDir, ProjectionTypes projection)
        {
            Trace.TraceInformation("{0}: Reading dataset..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            ImageFormat imageFormat = ImageFormat.Png;

            // Read and parse glacier bay dataset.
            // Define a color map with relief shading implemented.
            var datagridDetails = DataGridHelper.LoadFromFile(inputGrid);

            // Build a data grid using the input data set
            var dataGrid = new DataGrid(datagridDetails.Data, false);

            // Build the grid map for equirectangular projection using the data grid and boundary co-ordinates
            var equirectangularGridMap = new EquirectangularGridMap(dataGrid, datagridDetails.Boundary);

            // Build the color map using equirectangular projection grid map
            var dataColorMap = new ShadedReliefColorMap(equirectangularGridMap);

            var maximumLevelsOfDetail = 15;

            // Define an instance of ITileCreator to create image tiles.
            ITileCreator imageTileCreator = TileCreatorFactory.CreateImageTileCreator(dataColorMap, projection, outputDir);

            // Define an instance of ITileCreator to create DEM tiles.
            // Define serialization mechanism for storing and retrieving DEM tiles.
            ITileCreator demTileCreator = TileCreatorFactory.CreateDemTileCreator(dataColorMap, projection, outputDir);

            // MultiTile creator encapsulates image and DEM tile creators.
            var multiTileCreator = new MultiTileCreator(new Collection<ITileCreator>() { imageTileCreator, demTileCreator }, projection);

            // Define boundary for the region.
            var boundary = new Boundary(datagridDetails.Boundary.Left, datagridDetails.Boundary.Top, datagridDetails.Boundary.Right, datagridDetails.Boundary.Bottom);
            if (projection == ProjectionTypes.Toast)
            {
                boundary.Left += 180.0;
                boundary.Right += 180.0;
            }

            // Generate base tiles and fill up the pyramid.
            var tileGenerator = new TileGenerator(multiTileCreator);
            tileGenerator.Generate(maximumLevelsOfDetail, boundary);

            // Path of Mercator and Toast DEM tile server.
            const string MercatorDemTilePath = @"http://(web server address)?Q={0},{1},{2},Mercator,dem2178";
            const string ToastDemTilePath = @"http://(web server address)?Q={0},{1},{2},Toast,dem1033";

            string fileName = Path.GetFileNameWithoutExtension(inputGrid);

            // Generate Thumbnail Images.
            Trace.TraceInformation("{0}: Building Thumbnail image..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            ImageTileSerializer tileSerializer = new ImageTileSerializer(TileHelper.GetDefaultImageTilePathTemplate(outputDir), ImageFormat.Png);
            string thumbnailFile = Path.Combine(outputDir, fileName + ".jpeg");
            TileHelper.GenerateThumbnail(tileSerializer.GetFileName(0, 0, 0), 96, 45, thumbnailFile, ImageFormat.Jpeg);

            // Create and save WTML file.
            string textureTilePath = WtmlCollection.GetWtmlTextureTilePath(TileHelper.GetDefaultImageTilePathTemplate(outputDir), imageFormat.ToString());
            var inputBoundary = new Boundary(datagridDetails.Boundary.Left, datagridDetails.Boundary.Top, datagridDetails.Boundary.Right, datagridDetails.Boundary.Bottom);
            WtmlCollection wtmlCollection = new WtmlCollection(fileName, thumbnailFile, textureTilePath, maximumLevelsOfDetail, projection, inputBoundary);
            wtmlCollection.ZoomLevel = 0.2;
            wtmlCollection.IsElevationModel = true;
            wtmlCollection.DemTilePath = projection == ProjectionTypes.Mercator ? MercatorDemTilePath : ToastDemTilePath;
            string path = Path.Combine(outputDir, fileName + ".wtml");
            wtmlCollection.Save(path);
            Trace.TraceInformation("{0}: Collection successfully generated.", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
        }
Beispiel #7
0
 /// <summary>
 /// Generates all the tiles at the level specified and fills up the pyramid above 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 Generate(int level, Boundary boundary)
 {
     this.tilesProcessed = 0;
     this.BuildLevel(level, boundary);
     this.BuildParentLevels(level, boundary);
 }
Beispiel #8
0
        /// <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);
                }
            }
        }
Beispiel #9
0
        /// <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();
                        }
                    });
            }
        }
Beispiel #10
0
        /// <summary>
        /// This event is raised when the create pyramid function is called.
        /// </summary>
        /// <param name="sender">
        /// create ImageWorker.
        /// </param>
        /// <param name="e">
        /// DoWork EventArgs.
        /// </param>
        private void OnCreateImageWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            ImagePyramidDetails inputDetails = e.Argument as ImagePyramidDetails;
            if (inputDetails != null)
            {
                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.LoadingImage, PyramidGenerationStatus.Started);

                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.PyramidGeneration, PyramidGenerationStatus.Started);

                // Define ITileCreator instance for creating image tiles.
                // If the input projection type and output projection type is same then we need to tile the image.
                Core.ITileCreator tileCreator = null;

                // Calculates the estimated thumbnail generation time
                Stopwatch thumbnailGenerationStopwatch = new Stopwatch();
                thumbnailGenerationStopwatch.Start();
                if (inputDetails.InputProjection == InputProjections.EquiRectangular)
                {
                    // Read and initialize the image as an IGrid.
                    var imageGrid = new Core.ImageGrid(inputDetails.InputImagePath, true);
                    var equirectangularGridMap = new Core.EquirectangularGridMap(imageGrid, inputDetails.InputBoundary);
                    var imageColorMap = new Core.ImageColorMap(equirectangularGridMap);

                    tileCreator = Core.TileCreatorFactory.CreateImageTileCreator(
                        imageColorMap,
                        inputDetails.OutputProjection,
                        inputDetails.OutputDirectory);
                }
                else
                {
                    Core.IImageTileSerializer serializer = new Core.ImageTileSerializer(
                        Core.TileHelper.GetDefaultImageTilePathTemplate(inputDetails.OutputDirectory),
                        ImageFormat.Png);
                    tileCreator = new Core.TileChopper(inputDetails.InputImagePath, serializer, inputDetails.OutputProjection, inputDetails.InputBoundary);
                }

                thumbnailGenerationStopwatch.Stop();

                // Thumbnail estimated time is time required to load the image and then create the thumbnail with graphics
                this.ThumbnailEstimatedTime = thumbnailGenerationStopwatch.ElapsedMilliseconds * Constants.ThumbnailMultiplier;

                // Define plumbing for looping through all the tiles to be created for base image and pyramid.
                tileGenerator = new Core.TileGenerator(tileCreator);

                this.cancellationToken = new CancellationTokenSource();
                tileGenerator.ParallelOptions.CancellationToken = this.cancellationToken.Token;

                this.CheckCancel(e);

                // Define bounds of the image. Image is assumed to cover the entire world.
                // If not, change the coordinates accordingly.
                // For Mercator projection, longitude spans from -180 to +180 and latitude from 90 to -90.
                Core.Boundary gridBoundary = new Core.Boundary(
                    inputDetails.InputBoundary.Left,
                    inputDetails.InputBoundary.Top,
                    inputDetails.InputBoundary.Right,
                    inputDetails.InputBoundary.Bottom);
                if (inputDetails.OutputProjection == ProjectionTypes.Toast)
                {
                    // For Toast projection, longitude spans from 0 to +360 and latitude from 90 to -90.
                    gridBoundary.Left += 180;
                    gridBoundary.Right += 180;
                }

                // Start building base image and the pyramid.
                tileGenerator.Generate(inputDetails.Level, gridBoundary);

                if (inputDetails.IsGeneratePlate)
                {
                    NotifyMessage(PyramidGenerationSteps.PlateFileGeneration, PyramidGenerationStatus.Started);
                    this.CheckCancel(e);

                    // Generate Plate file.
                    Core.ImageTileSerializer pyramid = new Core.ImageTileSerializer(
                        Core.TileHelper.GetDefaultImageTilePathTemplate(inputDetails.OutputDirectory),
                        ImageFormat.Png);

                    plateGenerator = new Core.PlateFileGenerator(
                        System.IO.Path.Combine(inputDetails.OutputDirectory, inputDetails.OutputFilename + ".plate"),
                        inputDetails.Level,
                        ImageFormat.Png);

                    plateGenerator.CreateFromImageTile(pyramid);
                }

                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.ThumbnailGeneration, PyramidGenerationStatus.Started);

                // Generate Thumbnail Images.
                string thumbnailFile = System.IO.Path.Combine(inputDetails.OutputDirectory, inputDetails.OutputFilename + ".jpeg");
                Core.TileHelper.GenerateThumbnail(inputDetails.InputImagePath, 96, 45, thumbnailFile, ImageFormat.Jpeg);

                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.WTMLGeneration, PyramidGenerationStatus.Started);

                // Get the path of image tiles created and save it in WTML file.
                string pyramidPath = Core.WtmlCollection.GetWtmlTextureTilePath(Core.TileHelper.GetDefaultImageTilePathTemplate(inputDetails.OutputDirectory), ImageFormat.Png.ToString());

                Core.Boundary inputBoundary = new Core.Boundary(
                    inputDetails.InputBoundary.Left,
                    inputDetails.InputBoundary.Top,
                    inputDetails.InputBoundary.Right,
                    inputDetails.InputBoundary.Bottom);

                // Create and save WTML collection file.
                Core.WtmlCollection wtmlCollection = new Core.WtmlCollection(inputDetails.OutputFilename, thumbnailFile, pyramidPath, inputDetails.Level, inputDetails.OutputProjection, inputBoundary);
                wtmlCollection.Credit = inputDetails.Credits;
                wtmlCollection.CreditUrl = inputDetails.CreditsURL;
                string path = System.IO.Path.Combine(inputDetails.OutputDirectory, inputDetails.OutputFilename + ".wtml");
                wtmlCollection.Save(path);
            }
        }
Beispiel #11
0
 /// <summary>
 /// Check whether a given x,y tile coodinate belongs/overlap with the prefered regions' coordinates.
 /// </summary>
 /// <param name="preferredRegion">Region of preference.</param>
 /// <param name="level">Level at which the tile coordinate has to be examined.</param>
 /// <param name="tileX">Tile X coordinate.</param>
 /// <param name="tileY">Tile Y coordinate.</param>
 /// <returns>Boolean indicating the tile coordinates belongs/overlaps with the region of interest.</returns>
 private static bool IsDesiredTile(Boundary preferredRegion, int level, int tileX, int tileY)
 {
     OctTileMap octMap = new OctTileMap(level, tileX, tileY);
     Boundary tileBound = new Boundary(octMap.RaMin, octMap.DecMin, octMap.RaMax, octMap.DecMax);
     return IsBoundOrOverlap(tileBound, preferredRegion);
 }
 public void ValidateToastHelper()
 {
     int maxLevel = 15;
     var boundary = new Boundary(-136.40173 + 180, 58.35286, -135.91382 + 180, 58.75443);
     var tiles = ToastHelper.ComputeTileCoordinates(boundary, maxLevel);
     Assert.AreEqual(tiles.Count, maxLevel + 1);
 }
Beispiel #13
0
        /// <summary>
        /// This event is raised when the create pyramid function is called.
        /// </summary>
        /// <param name="sender">
        /// create ImageWorker.
        /// </param>
        /// <param name="e">
        /// DoWork EventArgs.
        /// </param>
        private void OnCreateImageWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            ImagePyramidDetails inputDetails = e.Argument as ImagePyramidDetails;

            if (inputDetails != null)
            {
                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.LoadingImage, PyramidGenerationStatus.Started);

                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.PyramidGeneration, PyramidGenerationStatus.Started);

                // Define ITileCreator instance for creating image tiles.
                // If the input projection type and output projection type is same then we need to tile the image.
                Core.ITileCreator tileCreator = null;

                // Calculates the estimated thumbnail generation time
                Stopwatch thumbnailGenerationStopwatch = new Stopwatch();
                thumbnailGenerationStopwatch.Start();
                if (inputDetails.InputProjection == InputProjections.EquiRectangular)
                {
                    // Read and initialize the image as an IGrid.
                    var imageGrid = new Core.ImageGrid(inputDetails.InputImagePath, true);
                    var equirectangularGridMap = new Core.EquirectangularGridMap(imageGrid, inputDetails.InputBoundary);
                    var imageColorMap          = new Core.ImageColorMap(equirectangularGridMap);

                    tileCreator = Core.TileCreatorFactory.CreateImageTileCreator(
                        imageColorMap,
                        inputDetails.OutputProjection,
                        inputDetails.OutputDirectory);
                }
                else
                {
                    Core.IImageTileSerializer serializer = new Core.ImageTileSerializer(
                        Core.TileHelper.GetDefaultImageTilePathTemplate(inputDetails.OutputDirectory),
                        ImageFormat.Png);
                    tileCreator = new Core.TileChopper(inputDetails.InputImagePath, serializer, inputDetails.OutputProjection, inputDetails.InputBoundary);
                }

                thumbnailGenerationStopwatch.Stop();

                // Thumbnail estimated time is time required to load the image and then create the thumbnail with graphics
                this.ThumbnailEstimatedTime = thumbnailGenerationStopwatch.ElapsedMilliseconds * Constants.ThumbnailMultiplier;

                // Define plumbing for looping through all the tiles to be created for base image and pyramid.
                tileGenerator = new Core.TileGenerator(tileCreator);

                this.cancellationToken = new CancellationTokenSource();
                tileGenerator.ParallelOptions.CancellationToken = this.cancellationToken.Token;

                this.CheckCancel(e);

                // Define bounds of the image. Image is assumed to cover the entire world.
                // If not, change the coordinates accordingly.
                // For Mercator projection, longitude spans from -180 to +180 and latitude from 90 to -90.
                Core.Boundary gridBoundary = new Core.Boundary(
                    inputDetails.InputBoundary.Left,
                    inputDetails.InputBoundary.Top,
                    inputDetails.InputBoundary.Right,
                    inputDetails.InputBoundary.Bottom);
                if (inputDetails.OutputProjection == ProjectionTypes.Toast)
                {
                    // For Toast projection, longitude spans from 0 to +360 and latitude from 90 to -90.
                    gridBoundary.Left  += 180;
                    gridBoundary.Right += 180;
                }

                // Start building base image and the pyramid.
                tileGenerator.Generate(inputDetails.Level, gridBoundary);

                if (inputDetails.IsGeneratePlate)
                {
                    NotifyMessage(PyramidGenerationSteps.PlateFileGeneration, PyramidGenerationStatus.Started);
                    this.CheckCancel(e);

                    // Generate Plate file.
                    Core.ImageTileSerializer pyramid = new Core.ImageTileSerializer(
                        Core.TileHelper.GetDefaultImageTilePathTemplate(inputDetails.OutputDirectory),
                        ImageFormat.Png);

                    plateGenerator = new Core.PlateFileGenerator(
                        System.IO.Path.Combine(inputDetails.OutputDirectory, inputDetails.OutputFilename + ".plate"),
                        inputDetails.Level,
                        ImageFormat.Png);

                    plateGenerator.CreateFromImageTile(pyramid);
                }

                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.ThumbnailGeneration, PyramidGenerationStatus.Started);

                // Generate Thumbnail Images.
                string thumbnailFile = System.IO.Path.Combine(inputDetails.OutputDirectory, inputDetails.OutputFilename + ".jpeg");
                Core.TileHelper.GenerateThumbnail(inputDetails.InputImagePath, 96, 45, thumbnailFile, ImageFormat.Jpeg);

                this.CheckCancel(e);

                NotifyMessage(PyramidGenerationSteps.WTMLGeneration, PyramidGenerationStatus.Started);

                // Get the path of image tiles created and save it in WTML file.
                string pyramidPath = Core.WtmlCollection.GetWtmlTextureTilePath(Core.TileHelper.GetDefaultImageTilePathTemplate(inputDetails.OutputDirectory), ImageFormat.Png.ToString());

                Core.Boundary inputBoundary = new Core.Boundary(
                    inputDetails.InputBoundary.Left,
                    inputDetails.InputBoundary.Top,
                    inputDetails.InputBoundary.Right,
                    inputDetails.InputBoundary.Bottom);

                // Create and save WTML collection file.
                Core.WtmlCollection wtmlCollection = new Core.WtmlCollection(inputDetails.OutputFilename, thumbnailFile, pyramidPath, inputDetails.Level, inputDetails.OutputProjection, inputBoundary);
                wtmlCollection.Credit    = inputDetails.Credits;
                wtmlCollection.CreditUrl = inputDetails.CreditsURL;
                string path = System.IO.Path.Combine(inputDetails.OutputDirectory, inputDetails.OutputFilename + ".wtml");
                wtmlCollection.Save(path);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Initializes a new instance of the TileChopper class
        /// </summary>
        /// <param name="fileName">
        /// Full path of the image.
        /// </param>
        /// <param name="serializer">
        /// Tile serializer.
        /// </param>
        /// <param name="projectionType">
        /// Projection type.
        /// </param>
        /// <param name="inputBoundary">
        /// Input boundary.
        /// </param>
        public TileChopper(string fileName, IImageTileSerializer serializer, ProjectionTypes projectionType, Boundary inputBoundary)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            }

            try
            {
                this.TileSerializer = serializer;
                this.projectionType = projectionType;
                this.inputBoundary  = inputBoundary;

                // Create a bitmap object and read the color pixels into the grid.
                using (Bitmap inputImage = new Bitmap(fileName))
                {
                    this.Initialize(inputImage);
                }
            }
            catch (OutOfMemoryException)
            {
                throw;
            }
            catch
            {
                string message = "An error occurred while reading input image file. Check the path and try again.";
                throw new InvalidOperationException(message);
            }
        }
Beispiel #15
0
        /// <summary>
        /// Processes a list of input image tiles and generates pyramid for level N.
        /// </summary>
        /// <param name="inputFilePath">Xml file with list of image tile information.</param>
        /// <param name="outputDir">Output directory where the image tiles of pyramid has to be stored.</param>
        /// <param name="projection">Projection to be used.</param>
        private static void ProcessMultipartEquirectangularImage(string inputFilePath, string outputDir, ProjectionTypes projection)
        {
            ImageFormat imageFormat = ImageFormat.Png;

            Trace.TraceInformation("{0}: Reading image..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));

            // Get the list of equirectangular images input.
            string[,] imageTiles = Program.GetInputImageList(inputFilePath);

            // Set the grid boundaries
            var imageBoundary = new Boundary(-180, -90, 180, 90);

            // Build an image grid using the input images
            var imageGrid = new ImageGrid(imageTiles, true);

            // Build the grid map for equirectangular projection using the image grid and boundary co-ordinates
            var equirectangularGridMap = new EquirectangularGridMap(imageGrid, imageBoundary);

            // Build the color map using equirectangular projection grid map
            var imageColorMap = new ImageColorMap(equirectangularGridMap);

            var maximumLevelsOfDetail = TileHelper.CalculateMaximumLevel(imageGrid.Height, imageGrid.Width, imageBoundary);

            // Define ITileCreator instance for creating image tiles.
            ITileCreator tileCreator = TileCreatorFactory.CreateImageTileCreator(imageColorMap, projection, outputDir);

            // Define plumbing for looping through all the tiles to be created for base image and pyramid.
            var tileGenerator = new TileGenerator(tileCreator);

            // Start building base image and the pyramid.
            Trace.TraceInformation("{0}: Building base and parent levels...", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            tileGenerator.Generate(maximumLevelsOfDetail);

            string fileName = Path.GetFileNameWithoutExtension(inputFilePath);

            // Generate Plate file.
            Trace.TraceInformation("{0}: Building Plate file...", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            ImageTileSerializer pyramid = new ImageTileSerializer(TileHelper.GetDefaultImageTilePathTemplate(outputDir), ImageFormat.Png);
            PlateFileGenerator plateGenerator = new PlateFileGenerator(
                Path.Combine(outputDir, fileName + ".plate"),
                maximumLevelsOfDetail,
                ImageFormat.Png);
            plateGenerator.CreateFromImageTile(pyramid);

            // Generate Thumbnail Images.
            Trace.TraceInformation("{0}: Building Thumbnail image..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            string thumbnailFile = Path.Combine(outputDir, fileName + ".jpeg");
            TileHelper.GenerateThumbnail(pyramid.GetFileName(0, 0, 0), 96, 45, thumbnailFile, ImageFormat.Jpeg);

            // Get the path of image tiles created and save it in WTML file.
            Trace.TraceInformation("{0}: Building WTML file..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            string pyramidPath = WtmlCollection.GetWtmlTextureTilePath(TileHelper.GetDefaultImageTilePathTemplate(outputDir), imageFormat.ToString());

            // Create and save WTML collection file.
            WtmlCollection wtmlCollection = new WtmlCollection(fileName, thumbnailFile, pyramidPath, maximumLevelsOfDetail, projection);
            string path = Path.Combine(outputDir, fileName + ".wtml");
            wtmlCollection.Save(path);
            Trace.TraceInformation("{0}: Collection successfully generated.", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
        }
Beispiel #16
0
        /// <summary>
        /// Processes a list of input image tiles and generates pyramid for level N.
        /// </summary>
        /// <param name="inputFilePath">Xml file with list of image tile information.</param>
        /// <param name="outputDir">Output directory where the image tiles of pyramid has to be stored.</param>
        /// <param name="projection">Projection to be used.</param>
        /// <param name="inputBoundary">Input image boundary.</param>
        private static void ProcessMultipartEquirectangularImage(string inputFilePath, string outputDir, ProjectionTypes projection, Boundary inputBoundary)
        {
            ImageFormat imageFormat = ImageFormat.Png;

            Trace.TraceInformation("{0}: Reading image..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));

            // Get the list of equirectangular images input.
            string[,] imageTiles = Program.GetInputImageList(inputFilePath);

            // Check if the image is circular.
            double longitudeDelta = inputBoundary.Right - inputBoundary.Left;
            bool circular = (360.0 - longitudeDelta) < 0.000001;

            // Build an image grid using the input images
            var imageGrid = new ImageGrid(imageTiles, circular);

            // Build the grid map for equirectangular projection using the image grid and boundary co-ordinates
            var equirectangularGridMap = new EquirectangularGridMap(imageGrid, inputBoundary);

            // Build the color map using equirectangular projection grid map
            var imageColorMap = new ImageColorMap(equirectangularGridMap);

            var maximumLevelsOfDetail = TileHelper.CalculateMaximumLevel(imageGrid.Height, imageGrid.Width, inputBoundary);

            // Define ITileCreator instance for creating image tiles.
            ITileCreator tileCreator = TileCreatorFactory.CreateImageTileCreator(imageColorMap, projection, outputDir);

            // Define bounds of the image. Image is assumed to cover the entire world.
            // If not, change the coordinates accordingly.
            // For Mercator projection, longitude spans from -180 to +180 and latitude from 90 to -90.
            Boundary gridBoundary = new Boundary(inputBoundary.Left, inputBoundary.Top, inputBoundary.Right, inputBoundary.Bottom);
            if (projection == ProjectionTypes.Toast)
            {
                // For Toast projection, longitude spans from 0 to +360 and latitude from 90 to -90.
                gridBoundary.Left += 180;
                gridBoundary.Right += 180;
            }

            // Define plumbing for looping through all the tiles to be created for base image and pyramid.
            var tileGenerator = new TileGenerator(tileCreator);

            // Start building base image and the pyramid.
            Trace.TraceInformation("{0}: Building base and parent levels...", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            tileGenerator.Generate(maximumLevelsOfDetail, gridBoundary);

            string fileName = Path.GetFileNameWithoutExtension(inputFilePath);

            // Generate Plate file.
            Trace.TraceInformation("{0}: Building Plate file...", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            ImageTileSerializer pyramid = new ImageTileSerializer(TileHelper.GetDefaultImageTilePathTemplate(outputDir), ImageFormat.Png);
            PlateFileGenerator plateGenerator = new PlateFileGenerator(
                Path.Combine(outputDir, fileName + ".plate"),
                maximumLevelsOfDetail,
                ImageFormat.Png);
            plateGenerator.CreateFromImageTile(pyramid);

            // Generate Thumbnail Images.
            Trace.TraceInformation("{0}: Building Thumbnail image..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            string thumbnailFile = Path.Combine(outputDir, fileName + ".jpeg");
            TileHelper.GenerateThumbnail(pyramid.GetFileName(0, 0, 0), 96, 45, thumbnailFile, ImageFormat.Jpeg);

            // Get the path of image tiles created and save it in WTML file.
            Trace.TraceInformation("{0}: Building WTML file..", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
            string pyramidPath = WtmlCollection.GetWtmlTextureTilePath(TileHelper.GetDefaultImageTilePathTemplate(outputDir), imageFormat.ToString());

            // Create and save WTML collection file.
            WtmlCollection wtmlCollection = new WtmlCollection(fileName, thumbnailFile, pyramidPath, maximumLevelsOfDetail, projection, inputBoundary);
            string path = Path.Combine(outputDir, fileName + ".wtml");
            wtmlCollection.Save(path);
            Trace.TraceInformation("{0}: Collection successfully generated.", DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture));
        }
Beispiel #17
0
        /// <summary>
        /// Checks if two bounding coordinates overlaps each other.
        /// </summary>
        /// <param name="region1">First region to be compared.</param>
        /// <param name="region2">Second region to be compared.</param>
        /// <returns>True/false indicating the overlap.</returns>
        private static bool IsBoundOrOverlap(Boundary region1, Boundary region2)
        {
            // Complete containment check, either region1 might engulf region2 or vice versa.
            // Check if region1 bounds point region2 OR region2 bounds region1
            if (region1.Left <= region2.Left && region1.Right >= region2.Right && region1.Top <= region2.Top && region1.Bottom >= region2.Bottom)
            {
                // Region1 bounds/surrounds region2
                return true;
            }
            else if (region2.Left <= region1.Left && region2.Right >= region1.Right && region2.Top <= region1.Top && region2.Bottom >= region1.Bottom)
            {
                // Region2 bounds/surrounds region1
                return true;
            }

            // Overlap check.
            if (((region2.Left >= region1.Left && region2.Left <= region1.Right) || (region2.Right >= region1.Left && region2.Right <= region1.Right)) &&
                ((region2.Top >= region1.Top && region2.Top <= region1.Bottom) || (region2.Bottom >= region1.Top && region2.Bottom <= region1.Bottom)))
            {
                // Now region2 coordinates overlaps(some coordinates of region2 lies inside of region1) with region1
                return true;
            }

            if (((region1.Left >= region2.Left && region1.Left <= region2.Right) || (region1.Right >= region2.Left && region1.Right <= region2.Right)) &&
               ((region1.Top >= region2.Top && region1.Top <= region2.Bottom) || (region1.Bottom >= region2.Top && region1.Bottom <= region2.Bottom)))
            {
                // Now region1 coordinates overlaps(some region1 coordinates lies inside of region2) with region2
                return true;
            }

            return false;
        }
Beispiel #18
0
        /// <summary>
        /// Initializes a new instance of the TileChopper class
        /// </summary>
        /// <param name="fileName">
        /// Full path of the image.
        /// </param>
        /// <param name="serializer">
        /// Tile serializer.
        /// </param>
        /// <param name="projectionType">
        /// Projection type.
        /// </param>
        /// <param name="inputBoundary">
        /// Input boundary.
        /// </param>
        public TileChopper(string fileName, IImageTileSerializer serializer, ProjectionTypes projectionType, Boundary inputBoundary)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            }

            try
            {
                this.TileSerializer = serializer;
                this.projectionType = projectionType;
                this.inputBoundary = inputBoundary;

                // Create a bitmap object and read the color pixels into the grid.
                using (Bitmap inputImage = new Bitmap(fileName))
                {
                    this.Initialize(inputImage);
                }
            }
            catch (OutOfMemoryException)
            {
                throw;
            }
            catch
            {
                string message = "An error occurred while reading input image file. Check the path and try again.";
                throw new InvalidOperationException(message);
            }
        }
Beispiel #19
0
        public WtmlCollection(string name, string thumbnailUrl, string textureTilePath, int numberOfLevels, ProjectionTypes type, Boundary inputBoundary)
        {
            this.Name            = name;
            this.PlaceName       = name;
            this.FolderName      = name;
            this.TextureTilePath = textureTilePath;
            this.NumberOfLevels  = numberOfLevels;
            this.ProjectionType  = type;
            this.ThumbnailUrl    = thumbnailUrl;

            // Assign default values.
            this.BaseDegreesPerTile = type == ProjectionTypes.Toast ? 90 : 360;
            this.BandPass           = BandPasses.Visible;
            this.DataSetType        = DataSetTypes.Earth;
            this.DemTilePath        = string.Empty;
            this.FileType           = ".png";
            this.QuadTreeMap        = string.Empty;

            if (inputBoundary != null)
            {
                // Calculate average latitude and longitude.
                this.Latitude  = (inputBoundary.Bottom + inputBoundary.Top) / 2;
                this.Longitude = (inputBoundary.Right + inputBoundary.Left) / 2;
            }
        }