/// <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); }
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); }