Пример #1
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);
        }
Пример #2
0
 internal void AddObstacle(IntervisibilityObstacle obstacle)
 {
     Obstacles.Add(obstacle);
 }