private IEnumerable <GeoSegment> GetDEMWestEastLines(List <FileMetadata> segTiles, GeoPoint northernSegPoint, GeoPoint southernSegPoint) { // Get the first north west tile and last south east tile. // The lines are bounded by those tiles foreach (var tilesByY in segTiles.GroupBy(t => t.StartLat).OrderByDescending(g => g.Key)) { List <FileMetadata> WETilesOrdered = tilesByY.OrderBy(t => t.StartLon).ToList(); FileMetadata left = WETilesOrdered.First(); FileMetadata right = WETilesOrdered.Last(); GeoPoint curPoint = new GeoPoint(left.StartLat, left.StartLon); // Y Index in tile coords int curIndex = (int)Math.Ceiling((left.StartLat - curPoint.Latitude) / left.PixelScaleY); while (IsPointInTile(left, curPoint)) { if (curIndex >= left.Height) { break; } curPoint.Latitude = left.StartLat + (left.pixelSizeY * curIndex); if (curPoint.Latitude < southernSegPoint.Latitude) { break; } GeoSegment line = new GeoSegment(new GeoPoint(curPoint.Latitude, left.OriginLongitude), new GeoPoint(curPoint.Latitude, right.EndLongitude)); curIndex++; yield return(line); } } }
public bool IsPointInTile(FileMetadata tileMetadata, GeoPoint point) { return(IsPointInTile(tileMetadata, point.Latitude, point.Longitude)); }
/// <summary> /// Finds all intersections between given segment and DEM grid /// </summary> /// <param name="startLon">Segment start longitude</param> /// <param name="startLat">Segment start latitude</param> /// <param name="endLon">Segment end longitude</param> /// <param name="endLat">Segment end latitude</param> /// <param name="segTiles">Metadata files <see cref="IElevationService.GetCoveringFiles"/> to see how to get them relative to segment geometry</param> /// <param name="returnStartPoint">If true, the segment starting point will be returned. Useful when processing a line segment by segment.</param> /// <param name="returnEndPoind">If true, the segment end point will be returned. Useful when processing a line segment by segment.</param> /// <returns></returns> private List <GeoPoint> FindSegmentIntersections(double startLon, double startLat, double endLon, double endLat, List <FileMetadata> segTiles, bool returnStartPoint, bool returnEndPoind) { List <GeoPoint> segmentPointsWithDEMPoints; // Find intersections with north/south lines, // starting form segment western point to easternmost point GeoPoint westernSegPoint = startLon < endLon ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); GeoPoint easternSegPoint = startLon > endLon ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); GeoSegment inputSegment = new GeoSegment(westernSegPoint, easternSegPoint); if (segTiles.Any()) { int estimatedCapacity = (segTiles.Select(t => t.OriginLongitude).Distinct().Count() // num horizontal tiles * width * segTiles.First().Width) + (segTiles.Select(t => t.OriginLatitude).Distinct().Count() // num vertical tiles * height * segTiles.First().Height); segmentPointsWithDEMPoints = new List <GeoPoint>(estimatedCapacity); bool yAxisDown = segTiles.First().pixelSizeY < 0; if (yAxisDown == false) { throw new NotImplementedException("DEM with y axis upwards not supported."); } foreach (GeoSegment demSegment in this.GetDEMNorthSouthLines(segTiles, westernSegPoint, easternSegPoint)) { if (GeometryService.LineLineIntersection(out GeoPoint intersectionPoint, inputSegment, demSegment)) { segmentPointsWithDEMPoints.Add(intersectionPoint); } } // Find intersections with west/east lines, // starting form segment northernmost point to southernmost point GeoPoint northernSegPoint = startLat > endLat ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); GeoPoint southernSegPoint = startLat < endLat ? new GeoPoint(startLat, startLon) : new GeoPoint(endLat, endLon); inputSegment = new GeoSegment(northernSegPoint, southernSegPoint); foreach (GeoSegment demSegment in this.GetDEMWestEastLines(segTiles, northernSegPoint, southernSegPoint)) { if (GeometryService.LineLineIntersection(out GeoPoint intersectionPoint, inputSegment, demSegment)) { segmentPointsWithDEMPoints.Add(intersectionPoint); } } } else { // No DEM coverage segmentPointsWithDEMPoints = new List <GeoPoint>(2); } // add start and/or end point if (returnStartPoint) { segmentPointsWithDEMPoints.Add(inputSegment.Start); } if (returnEndPoind) { segmentPointsWithDEMPoints.Add(inputSegment.End); } // sort points in segment order // segmentPointsWithDEMPoints.Sort(new DistanceFromPointComparer(new GeoPoint(startLat, startLon))); return(segmentPointsWithDEMPoints); }
private IEnumerable <GeoSegment> GetDEMNorthSouthLines(List <FileMetadata> segTiles, GeoPoint westernSegPoint, GeoPoint easternSegPoint) { // Get the first north west tile and last south east tile. // The lines are bounded by those tiles foreach (var tilesByX in segTiles.GroupBy(t => t.StartLon).OrderBy(g => g.Key)) { List <FileMetadata> NSTilesOrdered = tilesByX.OrderByDescending(t => t.StartLat).ToList(); FileMetadata top = NSTilesOrdered.First(); FileMetadata bottom = NSTilesOrdered.Last(); // TIP: can optimize here starting with min(westernSegPoint, startlon) but careful ! GeoPoint curPoint = new GeoPoint(top.StartLat, top.StartLon); // X Index in tile coords int curIndex = (int)Math.Ceiling((curPoint.Longitude - top.StartLon) / top.PixelScaleX); while (IsPointInTile(top, curPoint)) { if (curIndex >= top.Width) { break; } curPoint.Longitude = top.StartLon + (top.pixelSizeX * curIndex); if (curPoint.Longitude > easternSegPoint.Longitude) { break; } GeoSegment line = new GeoSegment(new GeoPoint(top.OriginLatitude, curPoint.Longitude), new GeoPoint(bottom.EndLatitude, curPoint.Longitude)); curIndex++; yield return(line); } } }
private IEnumerable <GeoSegment> GetDEMNorthSouthLines(List <FileMetadata> segTiles, GeoPoint westernSegPoint, GeoPoint easternSegPoint, double registrationOffsetPx) { // Get the first north west tile and last south east tile. // The lines are bounded by those tiles foreach (var tilesByX in segTiles.GroupBy(t => t.DataStartLon).OrderBy(g => g.Key)) { List <FileMetadata> NSTilesOrdered = tilesByX.OrderByDescending(t => t.DataStartLat).ToList(); FileMetadata top = NSTilesOrdered.First(); FileMetadata bottom = NSTilesOrdered.Last(); // TIP: can optimize here starting with min(westernSegPoint, startlon) but careful ! GeoPoint curPoint = new GeoPoint(top.DataStartLat, top.DataStartLon); // X Index in tile coords int curIndex = (int)Math.Ceiling((curPoint.Longitude - top.PhysicalStartLon) / top.PixelScaleX - registrationOffsetPx); // For cell registered datasets, DataStart is not matching the start data point. Start data point is at cell center (0.5 pixel off) double startLon = top.FileFormat.Registration == DEMFileRegistrationMode.Cell ? top.DataStartLon + top.PixelScaleX / 2d : top.DataStartLon; while (IsPointInTile(top, curPoint)) { if (curIndex >= top.Width) { break; } curPoint.Longitude = startLon + (top.pixelSizeX * curIndex); if (curPoint.Longitude > easternSegPoint.Longitude) { break; } GeoSegment line = new GeoSegment(new GeoPoint(top.DataEndLat, curPoint.Longitude), new GeoPoint(bottom.DataStartLat, curPoint.Longitude)); curIndex++; yield return(line); } } }
private IEnumerable <GeoSegment> GetDEMWestEastLines(List <FileMetadata> segTiles, GeoPoint northernSegPoint, GeoPoint southernSegPoint, double registrationOffsetPx) { // Get the first north west tile and last south east tile. // The lines are bounded by those tiles foreach (var tilesByY in segTiles.GroupBy(t => t.DataStartLat).OrderByDescending(g => g.Key)) { List <FileMetadata> WETilesOrdered = tilesByY.OrderBy(t => t.DataStartLon).ToList(); FileMetadata left = WETilesOrdered.First(); FileMetadata right = WETilesOrdered.Last(); GeoPoint curPoint = new GeoPoint(left.DataEndLat, left.DataStartLon); // For cell registered datasets, DataStart is not matching the start data point. Start data point is at cell center (0.5 pixel off) double endLat = left.FileFormat.Registration == DEMFileRegistrationMode.Cell ? left.DataEndLat + left.PixelScaleY / 2d : left.DataEndLat; // Y Index in tile coords int curIndex = (int)Math.Floor((left.PhysicalEndLat - curPoint.Latitude) / left.PixelScaleY - -registrationOffsetPx); while (IsPointInTile(left, curPoint)) { if (curIndex >= left.Height) { break; } curPoint.Latitude = endLat + (left.pixelSizeY * curIndex); if (curPoint.Latitude < southernSegPoint.Latitude) { break; } GeoSegment line = new GeoSegment(new GeoPoint(curPoint.Latitude, left.DataStartLon), new GeoPoint(curPoint.Latitude, right.DataEndLon)); curIndex++; yield return(line); } } }
public List <GeoPoint> GetLineGeometryElevation(IGeometry lineStringGeometry, DEMDataSet dataSet, InterpolationMode interpolationMode = InterpolationMode.Bilinear) { if (lineStringGeometry == null || lineStringGeometry.IsEmpty) { return(null); } if (lineStringGeometry.OgcGeometryType != OgcGeometryType.LineString) { throw new Exception("Geometry must be a linestring"); } if (lineStringGeometry.SRID != 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); var ptStart = lineStringGeometry.Coordinates[0]; var ptEnd = lineStringGeometry.Coordinates.Last(); GeoPoint start = new GeoPoint(ptStart.Y, ptStart.X); GeoPoint end = new GeoPoint(ptEnd.Y, ptEnd.X); double lengthMeters = start.DistanceTo(end); int demResolution = dataSet.ResolutionMeters; int totalCapacity = 2 * (int)(lengthMeters / demResolution); double registrationOffset = dataSet.FileFormat.Registration == DEMFileRegistrationMode.Cell ? 0 : 0.5; List <GeoPoint> geoPoints = new List <GeoPoint>(totalCapacity); using (RasterFileDictionary adjacentRasters = new RasterFileDictionary()) { bool isFirstSegment = true; // used to return first point only for first segments, for all other segments last point will be returned foreach (GeoSegment segment in lineStringGeometry.Segments()) { List <FileMetadata> segTiles = this.GetCoveringFiles(segment.GetBoundingBox(), dataSet, tiles); // Find all intersection with segment and DEM grid IEnumerable <GeoPoint> intersections = this.FindSegmentIntersections(segment.Start.Longitude , segment.Start.Latitude , segment.End.Longitude , segment.End.Latitude , segTiles , isFirstSegment , registrationOffset , true); // Get elevation for each point intersections = this.GetElevationData(intersections, adjacentRasters, segTiles, interpolator); // Add to output list geoPoints.AddRange(intersections); isFirstSegment = false; } //Debug.WriteLine(adjacentRasters.Count); } // Ensures all rasters are properly closed return(geoPoints); }
public static IEnumerable <GeoPoint> CenterOnOrigin(this IEnumerable <GeoPoint> points, GeoPoint origin) { return(points.Translate(-origin.Longitude, -origin.Latitude, -origin.Elevation ?? 0)); }
public static IEnumerable <GeoPoint> Translate(this IEnumerable <GeoPoint> points, GeoPoint vector) { foreach (var pt in points) { var pout = pt.Clone(); pout.Latitude += vector.Latitude; pout.Longitude += vector.Longitude; pout.Elevation += vector.Elevation ?? 0; yield return(pout); } }
/// <summary> /// Return visibility report from first point to last point. We assume that all points are aligned. /// WARNING: those calculations are not spherical (yet) and are not accurate for long distances. /// <see cref="IntervisibilityMetrics"/> /// </summary> /// <param name="points">Input list of points, visibility is calculated for first and last points (ie: are they visible or is there a relief standing in between)</param> /// <returns><see cref="IntervisibilityMetrics"/> object</returns> internal static IntervisibilityMetrics ComputeVisibilityMetrics(IList <GeoPoint> points, bool visibilityCheck = true, double sourceVerticalOffset = 0d, double targetVerticalOffset = 0, double?noDataValue = null) { IntervisibilityMetrics metrics = new IntervisibilityMetrics(); if (points.Count == 0) { return(metrics); } GeoPoint A = points.First(), B = points.Last(); double hA = A.Elevation ?? 0d, hB = B.Elevation ?? 0d; hA += sourceVerticalOffset; hB += targetVerticalOffset; double AB = A.DistanceTo(B); visibilityCheck = visibilityCheck && (AB > double.Epsilon); if (hA < hB) { MathHelper.Swap(ref A, ref B); MathHelper.Swap(ref hA, ref hB); } double total = 0, minElevation = double.MaxValue, maxElevation = double.MinValue, totalClimb = 0, totalDescent = 0; GeoPoint firstPoint = points[0]; firstPoint.DistanceFromOriginMeters = 0; // force at 0. If null, ignored in json responses double lastElevation = firstPoint.Elevation ?? 0; IntervisibilityObstacle obstacle = null; double lastPeakElevation = 0; int numNoDataPoints = 0; for (int i = 1; i < points.Count; i++) { #region metrics GeoPoint curPoint = points[i]; double v_dist = DistanceTo(curPoint, points[i - 1]); total += v_dist; curPoint.DistanceFromOriginMeters = total; minElevation = Math.Min(minElevation, curPoint.Elevation ?? double.MaxValue); maxElevation = Math.Max(maxElevation, curPoint.Elevation ?? double.MinValue); numNoDataPoints += curPoint.Elevation == noDataValue ? 1 : 0; double currentElevation = curPoint.Elevation ?? lastElevation; double diff = currentElevation - lastElevation; if (diff > 0) { totalClimb += diff; } else { totalDescent += diff; } #endregion #region visibility checks // Visibility check // If obstacle hit, add it and if (visibilityCheck) { double distToLowestPoint = curPoint.DistanceTo(B); double visibilityElevationThreshold = (distToLowestPoint * (hA - hB)) / AB + hB; if (currentElevation >= visibilityElevationThreshold) { if (obstacle == null) { obstacle = new IntervisibilityObstacle(curPoint, visibilityElevationThreshold); lastPeakElevation = currentElevation; obstacle.PeakPoint = curPoint; } else { // still inside obstacle, find peak if (currentElevation > lastPeakElevation) { lastPeakElevation = currentElevation; obstacle.PeakPoint = curPoint; } } } else { if (obstacle != null) // out of obstacle, register it { obstacle.ExitPoint = curPoint; metrics.AddObstacle(obstacle); obstacle = null; } } } if (i == points.Count - 1 && obstacle != null) { // Edge case: last point is exit point. We still have an active obstacle instance // If obstacle entry is curPoint, this is the same point and this is not an obstacle if (!obstacle.EntryPoint.Equals(curPoint)) { obstacle.ExitPoint = curPoint; metrics.AddObstacle(obstacle); obstacle = null; } } #endregion lastElevation = currentElevation; } metrics.Climb = totalClimb; metrics.Descent = totalDescent; metrics.NumPoints = points.Count; metrics.Distance = total; metrics.MinElevation = minElevation; metrics.MaxElevation = maxElevation; metrics.HasVoids = numNoDataPoints > 0; metrics.NumVoidPoints = numNoDataPoints; return(metrics); }
public static Vector3 AsVector3(this GeoPoint geoPoint) { return(new Vector3((float)geoPoint.Longitude, (float)geoPoint.Latitude, (float)(geoPoint.Elevation ?? 0D))); }
public static Vector3 ToVector3GlTFSpace(this GeoPoint geoPoint) { return(ToGlTFSpace(new Vector3((float)geoPoint.Longitude, (float)geoPoint.Latitude, (float)(geoPoint.Elevation ?? 0D)))); }
public IntervisibilityObstacle(GeoPoint entryPoint, double visibilityElevationThreshold) { this.EntryPoint = entryPoint; this.VisibilityElevationThreshold = visibilityElevationThreshold; }
public static Vector3 ToVector3(this GeoPoint geoPoint) { return(new Vector3((float)geoPoint.Longitude, (float)geoPoint.Elevation, -(float)geoPoint.Latitude)); }
public GeoPoint GetPointElevation(GeoPoint location, DEMDataSet dataSet, InterpolationMode interpolationMode = InterpolationMode.Bilinear) { return(GetPointElevation(location.Latitude, location.Longitude, dataSet, interpolationMode)); }
public static BoundingBox AroundPoint(GeoPoint point, double size) { return(BoundingBox.AroundPoint(point.Latitude, point.Longitude, size)); }
public GeoSegment(GeoPoint start, GeoPoint end) { Start = start; End = end; }