public List <GeoPoint> GetLineGeometryElevation(SqlGeometry lineStringGeometry, DEMDataSet dataSet, InterpolationMode interpolationMode = InterpolationMode.Bilinear) { if (lineStringGeometry == null || lineStringGeometry.IsNull) { return(null); } if (lineStringGeometry.STGeometryType().Value != "LineString") { throw new Exception("Geometry must be a linestring"); } if (lineStringGeometry.STSrid.Value != 4326) { throw new Exception("Geometry SRID must be set to 4326 (WGS 84)"); } BoundingBox bbox = lineStringGeometry.GetBoundingBox(); List <FileMetadata> tiles = this.GetCoveringFiles(bbox, dataSet); // Init interpolator IInterpolator interpolator = GetInterpolator(interpolationMode); double lengthMeters = lineStringGeometry.STLength().Value; int demResolution = dataSet.ResolutionMeters; int totalCapacity = 2 * (int)(lengthMeters / demResolution); List <GeoPoint> geoPoints = new List <GeoPoint>(totalCapacity); using (GeoTiffDictionary adjacentGeoTiffs = new GeoTiffDictionary()) { bool isFirstSegment = true; // used to return first point only for first segments, for all other segments last point will be returned foreach (SqlGeometry segment in lineStringGeometry.Segments()) { List <FileMetadata> segTiles = this.GetCoveringFiles(segment.GetBoundingBox(), dataSet, tiles); // Find all intersection with segment and DEM grid List <GeoPoint> intersections = this.FindSegmentIntersections(segment.STStartPoint().STX.Value , segment.STStartPoint().STY.Value , segment.STEndPoint().STX.Value , segment.STEndPoint().STY.Value , segTiles , isFirstSegment , true); // Get elevation for each point this.GetElevationData(ref intersections, adjacentGeoTiffs, segTiles, interpolator); // Add to output list geoPoints.AddRange(intersections); isFirstSegment = false; } //Debug.WriteLine(adjacentGeoTiffs.Count); } // Ensures all geotifs are properly closed return(geoPoints); }
/// <summary> /// Fill altitudes for each GeoPoint provided, opening as few GeoTiffs as possible /// </summary> /// <param name="intersections"></param> /// <param name="segTiles"></param> public void GetElevationData(ref List <GeoPoint> intersections, GeoTiffDictionary adjacentGeoTiffs, List <FileMetadata> segTiles, IInterpolator interpolator) { // Group by tiff file for sequential and faster access var pointsByTileQuery = from point in intersections let pointTile = new { Point = point, Tile = segTiles.FirstOrDefault(t => this.IsPointInTile(t, point)), AdjacentTiles = segTiles.Where(t => this.IsPointInAdjacentTile(t, point)).ToList() } group pointTile by pointTile.Tile into pointsByTile where pointsByTile.Key != null select pointsByTile; try { float lastElevation = 0; // To interpolate well points close to tile edges, we need all adjacent tiles //using (GeoTiffDictionary adjacentGeoTiffs = new GeoTiffDictionary()) //{ // For each group (key = tile, values = points within this tile) // TIP: test use of Parallel (warning : a lot of files may be opened at the same time) foreach (var tilePoints in pointsByTileQuery) { // Get the tile FileMetadata mainTile = tilePoints.Key; // We open geotiffs first, then we iterate PopulateGeoTiffDictionary(adjacentGeoTiffs, mainTile, _IGeoTiffService, tilePoints.SelectMany(tp => tp.AdjacentTiles)); foreach (var pointile in tilePoints) { GeoPoint current = pointile.Point; lastElevation = this.ParseGeoDataAtPoint(adjacentGeoTiffs, mainTile, current.Latitude, current.Longitude, lastElevation, interpolator); current.Elevation = lastElevation; } //adjacentGeoTiffs.Clear(); } } //} catch (Exception e) { Trace.TraceError($"Error while getting elevation data : {e.Message}{Environment.NewLine}{e.ToString()}"); } }
private void PopulateGeoTiffDictionary(GeoTiffDictionary dictionary, FileMetadata mainTile, IGeoTiffService geoTiffService, IEnumerable <FileMetadata> fileMetadataList) { // Add main tile if (!dictionary.ContainsKey(mainTile)) { dictionary[mainTile] = geoTiffService.OpenFile(mainTile.Filename); } foreach (var fileMetadata in fileMetadataList) { if (!dictionary.ContainsKey(fileMetadata)) { dictionary[fileMetadata] = geoTiffService.OpenFile(fileMetadata.Filename); } } }
private float GetElevationAtPoint(FileMetadata mainTile, GeoTiffDictionary tiles, int x, int y, float nullValue) { int xRemap, yRemap; FileMetadata goodTile = FindTile(mainTile, tiles, x, y, out xRemap, out yRemap); if (goodTile == null) { return(nullValue); } if (tiles.ContainsKey(goodTile)) { return(tiles[goodTile].ParseGeoDataAtPoint(goodTile, xRemap, yRemap)); } else { throw new Exception("Tile not found. Should not happen."); } }
private FileMetadata FindTile(FileMetadata mainTile, GeoTiffDictionary tiles, int x, int y, out int newX, out int newY) { int xTileOffset = x < 0 ? -1 : x >= mainTile.Width ? 1 : 0; int yTileOffset = y < 0 ? -1 : y >= mainTile.Height ? 1 : 0; if (xTileOffset == 0 && yTileOffset == 0) { newX = x; newY = y; return(mainTile); } else { int yScale = Math.Sign(mainTile.pixelSizeY); FileMetadata tile = tiles.Keys.FirstOrDefault( t => t.OriginLatitude == mainTile.OriginLatitude + yScale * yTileOffset && t.OriginLongitude == mainTile.OriginLongitude + xTileOffset); newX = xTileOffset > 0 ? x % mainTile.Width : (mainTile.Width + x) % mainTile.Width; newY = yTileOffset < 0 ? (mainTile.Height + y) % mainTile.Height : y % mainTile.Height; return(tile); } }
public GeoPoint GetPointElevation(double lat, double lon, DEMDataSet dataSet, InterpolationMode interpolationMode = InterpolationMode.Bilinear) { GeoPoint geoPoint = new GeoPoint(lat, lon); List <FileMetadata> tiles = this.GetCoveringFiles(lat, lon, dataSet); // Init interpolator IInterpolator interpolator = GetInterpolator(interpolationMode); List <GeoPoint> geoPoints = new List <GeoPoint>(); using (GeoTiffDictionary adjacentGeoTiffs = new GeoTiffDictionary()) { PopulateGeoTiffDictionary(adjacentGeoTiffs, tiles.First(), _IGeoTiffService, tiles); geoPoint.Elevation = ParseGeoDataAtPoint(adjacentGeoTiffs, tiles.First(), lat, lon, 0, interpolator); //Debug.WriteLine(adjacentGeoTiffs.Count); } // Ensures all geotifs are properly closed return(geoPoint); }
public float ParseGeoDataAtPoint(GeoTiffDictionary adjacentTiles, FileMetadata metadata, double lat, double lon, float lastElevation, IInterpolator interpolator) { float heightValue = 0; try { IGeoTiff mainTiff = adjacentTiles[metadata]; //const double epsilon = (Double.Epsilon * 100); float noData = metadata.NoDataValueFloat; // precise position on the grid (with commas) double ypos = (lat - metadata.StartLat) / metadata.pixelSizeY; double xpos = (lon - metadata.StartLon) / metadata.pixelSizeX; // If pure integers, then it's on the grid float xInterpolationAmount = (float)xpos % 1; float yInterpolationAmount = (float)ypos % 1; bool xOnGrid = xInterpolationAmount == 0; bool yOnGrid = yInterpolationAmount == 0; // If xOnGrid and yOnGrid, we are on a grid intersection, and that's all if (xOnGrid && yOnGrid) { int x = (int)Math.Round(xpos, 0); int y = (int)Math.Round(ypos, 0); var tile = FindTile(metadata, adjacentTiles, x, y, out x, out y); heightValue = mainTiff.ParseGeoDataAtPoint(tile, x, y); } else { int xCeiling = (int)Math.Ceiling(xpos); int xFloor = (int)Math.Floor(xpos); int yCeiling = (int)Math.Ceiling(ypos); int yFloor = (int)Math.Floor(ypos); // Get 4 grid nearest points (DEM grid corners) // If not yOnGrid and not xOnGrid we are on grid horizontal line // We need elevations for top, bottom, left and right grid points (along x axis and y axis) float northWest = GetElevationAtPoint(metadata, adjacentTiles, xFloor, yFloor, NO_DATA_OUT); float northEast = GetElevationAtPoint(metadata, adjacentTiles, xCeiling, yFloor, NO_DATA_OUT); float southWest = GetElevationAtPoint(metadata, adjacentTiles, xFloor, yCeiling, NO_DATA_OUT); float southEast = GetElevationAtPoint(metadata, adjacentTiles, xCeiling, yCeiling, NO_DATA_OUT); float avgHeight = GetAverageExceptForNoDataValue(noData, NO_DATA_OUT, southWest, southEast, northWest, northEast); if (northWest == noData) { northWest = avgHeight; } if (northEast == noData) { northEast = avgHeight; } if (southWest == noData) { southWest = avgHeight; } if (southEast == noData) { southEast = avgHeight; } heightValue = interpolator.Interpolate(southWest, southEast, northWest, northEast, xInterpolationAmount, yInterpolationAmount); } if (heightValue == NO_DATA_OUT) { heightValue = lastElevation; } } catch (Exception e) { Trace.TraceError($"Error while getting elevation data : {e.Message}{Environment.NewLine}{e.ToString()}"); } return(heightValue); }