/// <summary>
        /// Tries to use the DEM stored in memory.
        /// </summary>
        /// <returns>NULL if the in-memory DEM is not available.</returns>
        private RasterDigitalElevationModelBase TryMemory()
        {
            RasterDigitalElevationModelBase result = null;
            long maxBytes = 1024 * 1024 * 1024 * 2L;         // 2 GiB

            // 2 GiB is the .NET limit for allocating RAM, at least in 2.0.
            // See https://stackoverflow.com/questions/1087982/single-objects-still-limited-to-2-gb-in-size-in-clr-4-0
            if (RequiredBytes > maxBytes)
            {
                this.ActivityLogger.LogFormat(ActivityLogLevel.Warning,
                                              "In-memory cache not available due to DEM size of {0} MiB bigger than 2 GiB.", RequiredMebibytes);
                return(null);
            }

            try
            {
                result = new MemoryBasedRasterDigitalElevationModel(
                    lonResolution, latResolution, lonOffset, latOffset, lonLength, latLength);
            }
            catch (OverflowException)
            {
                return(null);
            }
            catch (OutOfMemoryException)
            {
                this.ActivityLogger.LogFormat(ActivityLogLevel.Warning,
                                              "In-memory cache not available due to not enough free memory. DEM needs {0} MiB.", RequiredMebibytes);
                return(null);
            }

            return(result);
        }
        /// <summary>
        /// Returns a suitable DEM storage which is supported by the executing system.
        /// </summary>
        /// <returns>NULL if no model is available.</returns>
        public RasterDigitalElevationModelBase CreateSupportedModel()
        {
            RasterDigitalElevationModelBase result = null;

            // First of all try to save the DEM in memory
            result = TryMemory();

            // If this fails try the filesystem
            if (result == null)
            {
                result = TryFilesystem();
            }

            if (result is FileBasedRasterDigitalElevationModel)
            {
                string msg = "Using the filesystem as cache. This will take a huge amount of time, be patient.";
                msg += " It will also create a {0} MiB file in your location for temporary files.";

                this.ActivityLogger.LogFormat(ActivityLogLevel.Warning, msg, RequiredMebibytes);
            }

            return(result);
        }
Ejemplo n.º 3
0
        public IDigitalElevationModel LoadDemForArea(Bounds2 bounds)
        {
            // make sure the cache directory exists
            if (false == Directory.Exists(srtm3CachePath))
            {
                Directory.CreateDirectory(srtm3CachePath);
            }

            // first create a list of geographicals cells which constitute the specified area
            IDictionary <int, Srtm3Cell> cellsToUse = new Dictionary <int, Srtm3Cell> ();

            for (int lat = CalculateCellDegrees(bounds.MinY); lat <= CalculateCellDegrees(bounds.MaxY); lat++)
            {
                for (int lng = CalculateCellDegrees(bounds.MinX); lng <= CalculateCellDegrees(bounds.MaxX); lng++)
                {
                    Srtm3Cell cell = new Srtm3Cell((Int16)lng, (Int16)lat);
                    cellsToUse.Add(Srtm3Cell.CalculateCellKey(cell), cell);
                }
            }

            // then fetch a list of already downloaded cells
            IDictionary <int, Srtm3Cell> cachedCells = FetchCachedCellsList();

            try
            {
                foreach (Srtm3Cell cell in cellsToUse.Values)
                {
                    // if it is not cached...
                    if (false == cachedCells.ContainsKey(Srtm3Cell.CalculateCellKey(cell)))
                    {
                        // find the right subdirectory
                        SrtmContinentalRegion continentalRegion = (SrtmContinentalRegion)index.GetValueForCell(cell.CellLon, cell.CellLat);

                        if (continentalRegion == SrtmContinentalRegion.None)
                        {
                            // the cell does not exist in the index, it is probably an ocean cell
                            // add an empty cell to the cache and go to the next cell
                            cachedCells.Add(Srtm3Cell.CalculateCellKey(cell), cell);
                            continue;
                        }

                        string filename = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.zip", cell.CellFileName);
                        string url      = srtmSource + continentalRegion.ToString() + "/" + filename;

                        string localFilename = Path.Combine(srtm3CachePath, filename);

                        this.activityLogger.Log(ActivityLogLevel.Verbose, "Downloading SRTM cell " + cell.CellFileName);

                        WebRequest  request  = WebRequest.Create(new System.Uri(url));
                        WebResponse response = request.GetResponse();
                        // Get the stream containing content returned by the server.
                        Stream dataStream = response.GetResponseStream();

                        FileStream fileStream = new FileStream(localFilename, FileMode.OpenOrCreate);

                        //Download in chuncks
                        byte[] buffer = new byte[1024];
                        int    bytesRead;
                        while ((bytesRead = dataStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fileStream.Write(buffer, 0, bytesRead);
                        }
                        long receivedLength = fileStream.Length;
                        fileStream.Close();
                        dataStream.Close();
                        response.Close();

                        // Check if the download is complete.
                        if (response.ContentLength != -1 && response.ContentLength > receivedLength)
                        {
                            File.Delete(localFilename);
                            throw new WebException("Download incomplete (content length mismatch).", null, WebExceptionStatus.ReceiveFailure, response);
                        }

                        // unzip it and delete the zip file
                        FastZip zip = new FastZip();
                        zip.ExtractZip(localFilename, srtm3CachePath, null);
                        File.Delete(localFilename);
                    }

                    // now load it
                    cell.LoadFromCache(srtm3CachePath);
                }
            }
            finally
            {
            }

            // create elevation data
            int west, south, east, north;

            west  = Srtm3Storage.CalculateCellPosition(bounds.MinX);
            south = Srtm3Storage.CalculateCellPosition(bounds.MinY);
            east  = Srtm3Storage.CalculateCellPosition(bounds.MaxX);
            north = Srtm3Storage.CalculateCellPosition(bounds.MaxY);

            int width  = east - west + 1;
            int height = north - south + 1;

            long requiredBytes = width * height * 2L;
            int  loadCounter   = 1;

            RasterDigitalElevationModelFactory factory = new RasterDigitalElevationModelFactory(1200, 1200, west, south, width, height);

            factory.ActivityLogger = activityLogger;
            RasterDigitalElevationModelBase dem = factory.CreateSupportedModel();

            if (dem == null)
            {
                throw new PlatformNotSupportedException("No suitable location for the DEM found.");
            }

            // and fill the DEM with each cell points
            foreach (Srtm3Cell cell in cellsToUse.Values)
            {
                this.activityLogger.LogFormat(ActivityLogLevel.Normal,
                                              "Loading cell {0} of {1} into DEM", loadCounter++, cellsToUse.Values.Count);

                dem.CopyElevationPointsFrom(cell);
            }

            return(dem);
        }