Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow arbitrary altitude in source / target in ElevationService.GetIntervisibilityReport #89

Open
rurounijones opened this issue Mar 13, 2021 · 1 comment
Assignees

Comments

@rurounijones
Copy link

rurounijones commented Mar 13, 2021

Is your feature request related to a problem? Please describe.
The use-case I have is to determine if two aircraft have line of sight to each other. Each aircraft's position is defined by their Latitude, Longitude and Altitude above Mean Sea Level (MSL)

I have been messing around with the Intervisibility report and it doesn't quite support this use-case. I believe what is happening is:

Currently when you perform an intervisibility report you can pass in GeoPoints with elevation specified but that field is ignored since the LineString used in the method only provides 2D points and then the elevation is calculated based on those points

You can optionally specify a verticalOffset from that elevation for both the source and the target in GetIntervisibilityReport but that doesn't allow you to specify an arbitrary altitude, only an offset from the ground elevation which we do not know in advance for this use-case

Describe the solution you'd like

For this use-case all I actually need is a simple bool ElevationService.HasLineOfSight(sourcePoint, targetPoint, dataSet) as even the Intervisibility report is overkill as all I need is the boolean "yes/no" which means we could stop the calculation the first time an obstacle is detected which may same some processing time.

However, I will assume we keep using the Intervisibility report method since it is already written and easily (I think) modified

I would like the Intervisibility report to support the elevation/altitude field in the GeoPoints passed to it.

var sourcePoint = new GeoPoint(source.Latitude, source.Longitude, source.Altitude);
var targetPoint = new GeoPoint(target.Latitude, target.Longitude, target.Altitude);
var report = ElevationService.GetIntervisibilityReport(sourcePoint, targetPoint)

And I think it could be done very easily but since this is all new to me I would like to confirm here.

In the GetIntervisibilityReport method we need to reset the elevation of the source and target points, if they are provided, before performing the visibility calculations.

        public IntervisibilityReport GetIntervisibilityReport(GeoPoint source, GeoPoint target, DEMDataSet dataSet
            , bool downloadMissingFiles = true
            , double sourceVerticalOffset = 0d
            , double targetVerticalOffset = 0d
            , InterpolationMode interpolationMode = InterpolationMode.Bilinear)
        {
            try
            {
                var elevationLine = GeometryService.ParseGeoPointAsGeometryLine(source, target);

                if (downloadMissingFiles)
                    this.DownloadMissingFiles(dataSet, elevationLine.GetBoundingBox());

                var geoPoints = this.GetLineGeometryElevation(elevationLine, dataSet);

                // New code
                if (source.Elevation != null)
                {
                    geoPoints[0].Elevation = source.Elevation;
                }
                if (target.Elevation != null && geoPoints.Count > 1)
                {
                    geoPoints[geoPoints.Count -1].Elevation = target.Elevation;
                }
                // End new code

                if (dataSet.SRID != Reprojection.SRID_GEODETIC)
                    geoPoints = geoPoints.ReprojectTo(dataSet.SRID, Reprojection.SRID_GEODETIC).ToList();

                var metrics = geoPoints.ComputeVisibilityMetrics(sourceVerticalOffset, targetVerticalOffset, dataSet.NoDataValue);

                return new IntervisibilityReport(geoPoints, metrics, originVerticalOffset: sourceVerticalOffset, targetVerticalOffset: targetVerticalOffset);
            }
            catch (Exception ex)
            {
                _logger.LogError($"{nameof(GetIntervisibilityReport)} error: {ex.Message}");
                throw;
            }

Describe alternatives you've considered
I haven't tried it yet but looking at the code I think I could do this myself by cutting bits of code out and stitching it together myself then calling GetIntervisibilityReport(List<GeoPoint> ... ) but this seems a not-great solution since I am duplicating code in the library that could get out of sync.

One other thing to consider is that this change might not be considered backwards compatible if people are passing in GeoPoints to this method that have altitudes which are currently being ignored.

Additional context
Intervisibility report highlighting the issue where I was doing some experimenting with specifying vertical offsets etc.

var sourcePoint = new GeoPoint(source.Location.Coordinate.Latitude, source.Location.Coordinate.Longitude, source.Altitude);
var targetPoint = new GeoPoint(target.Location.Coordinate.Latitude, target.Location.Coordinate.Longitude, target.Altitude);
var report = ElevationService.GetIntervisibilityReport(sourcePoint, targetPoint, DataSet, true, source.Altitude, target.Altitude);
LOS report:
Source: E-3A 'USA air 3 unit1', Lat/Lon: 44.9440589/37.5337401 at 9138.08 meters
Target: Su-33 'RUSSIA air 21 unit1', Lat/Lon: 42.802319/41.0292858 at 2029.22 meters
Report:
  Origin: Lat/Lon 44.9440589/37.5337401. elevation 458.7944641113281, vertical offset 9138.08
  Target: Lat/Lon 42.802319/41.0292858. elevation 6991.50341796875, vertical offset 2029.22
  Obstructed: True
  Obstacles count: 552
  Metrics: Min/Max: -32517.84 / 32522.96, Distance: 368135.30 m, Climb/Descent: 23523479.52 / -23516946.82
@rurounijones
Copy link
Author

rurounijones commented Mar 13, 2021

In the end it wasn't that painful. I just ended up doing

            var sourcePoint = new GeoPoint(source.Location.Coordinate.Latitude, source.Location.Coordinate.Longitude);
            var targetPoint = new GeoPoint(target.Location.Coordinate.Latitude, target.Location.Coordinate.Longitude);

            var elevationLine = GeometryService.ParseGeoPointAsGeometryLine(sourcePoint, targetPoint);
            var geoPoints = ElevationService.GetLineGeometryElevation(elevationLine, DataSet);

            geoPoints[0].Elevation = source.Altitude;
            geoPoints[^1].Elevation = target.Altitude;

            var metrics = geoPoints.ComputeVisibilityMetrics(0d, 0d, DataSet.NoDataValue);
            var report = new IntervisibilityReport(geoPoints, metrics, originVerticalOffset: 0d, targetVerticalOffset: 0d);

It may be worth adding a bit of documentation regarding how the intervisibility report is based only on calculated elevation + offset and that elevation in the GeoPoints it ignored when passing in just a source and target.

@xfischer xfischer self-assigned this Sep 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants