예제 #1
0
        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);
                }
            }
        }
예제 #2
0
 public bool IsPointInTile(FileMetadata tileMetadata, GeoPoint point)
 {
     return(IsPointInTile(tileMetadata, point.Latitude, point.Longitude));
 }
예제 #3
0
        /// <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);
        }
예제 #4
0
        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);
                }
            }
        }
예제 #5
0
        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);
                }
            }
        }
예제 #6
0
        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);
                }
            }
        }
예제 #7
0
        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);
        }
예제 #8
0
 public static IEnumerable <GeoPoint> CenterOnOrigin(this IEnumerable <GeoPoint> points, GeoPoint origin)
 {
     return(points.Translate(-origin.Longitude, -origin.Latitude, -origin.Elevation ?? 0));
 }
예제 #9
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);
     }
 }
예제 #10
0
        /// <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);
        }
예제 #11
0
 public static Vector3 AsVector3(this GeoPoint geoPoint)
 {
     return(new Vector3((float)geoPoint.Longitude, (float)geoPoint.Latitude, (float)(geoPoint.Elevation ?? 0D)));
 }
예제 #12
0
 public static Vector3 ToVector3GlTFSpace(this GeoPoint geoPoint)
 {
     return(ToGlTFSpace(new Vector3((float)geoPoint.Longitude, (float)geoPoint.Latitude, (float)(geoPoint.Elevation ?? 0D))));
 }
예제 #13
0
 public IntervisibilityObstacle(GeoPoint entryPoint, double visibilityElevationThreshold)
 {
     this.EntryPoint = entryPoint;
     this.VisibilityElevationThreshold = visibilityElevationThreshold;
 }
예제 #14
0
 public static Vector3 ToVector3(this GeoPoint geoPoint)
 {
     return(new Vector3((float)geoPoint.Longitude, (float)geoPoint.Elevation, -(float)geoPoint.Latitude));
 }
예제 #15
0
 public GeoPoint GetPointElevation(GeoPoint location, DEMDataSet dataSet, InterpolationMode interpolationMode = InterpolationMode.Bilinear)
 {
     return(GetPointElevation(location.Latitude, location.Longitude, dataSet, interpolationMode));
 }
예제 #16
0
 public static BoundingBox AroundPoint(GeoPoint point, double size)
 {
     return(BoundingBox.AroundPoint(point.Latitude, point.Longitude, size));
 }
예제 #17
0
파일: GeoSegment.cs 프로젝트: zy6p/DEM.Net
 public GeoSegment(GeoPoint start, GeoPoint end)
 {
     Start = start;
     End   = end;
 }