121 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using MetadataExtractor;
 | |
| using Phares.Shared.Models;
 | |
| 
 | |
| namespace Phares.Metadata.Models.Stateless;
 | |
| 
 | |
| internal abstract class GPS
 | |
| {
 | |
| 
 | |
|     private static bool CoordinateValidatorValidate(double latitude, double longitude)
 | |
|     {
 | |
|         if (latitude is < (-90) or > 90)
 | |
|             return false;
 | |
|         if (longitude is < (-180) or > 180)
 | |
|             return false;
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     private static double GetRadius(IMetadata.DistanceUnit distanceUnit)
 | |
|     {
 | |
|         return distanceUnit switch
 | |
|         {
 | |
|             IMetadata.DistanceUnit.Kilometers => 6371.0, // EarthRadiusInKilometers;
 | |
|             IMetadata.DistanceUnit.Meters => 6371000.0, // EarthRadiusInMeters;
 | |
|             IMetadata.DistanceUnit.NauticalMiles => 3440.0, // EarthRadiusInNauticalMiles;
 | |
|             IMetadata.DistanceUnit.Miles => 3959.0, // EarthRadiusInMiles;
 | |
|             _ => throw new NotSupportedException()
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     private static double ToRadian(double d) =>
 | |
|         d * (Math.PI / 180);
 | |
| 
 | |
|     private static double DiffRadian(double val1, double val2) =>
 | |
|         ToRadian(val2) - ToRadian(val1);
 | |
| 
 | |
|     internal static double GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, IMetadata.DistanceUnit distanceUnit = IMetadata.DistanceUnit.Miles)
 | |
|     {
 | |
|         if (!CoordinateValidatorValidate(originLatitude, originLongitude))
 | |
|             throw new ArgumentException("Invalid origin coordinates supplied.");
 | |
|         if (!CoordinateValidatorValidate(destinationLatitude, destinationLongitude))
 | |
|             throw new ArgumentException("Invalid destination coordinates supplied.");
 | |
|         double radius = GetRadius(distanceUnit);
 | |
|         return Math.Round(
 | |
|                 radius * 2 *
 | |
|                 Math.Asin(Math.Min(1,
 | |
|                                    Math.Sqrt(
 | |
|                                        Math.Pow(Math.Sin(DiffRadian(originLatitude, destinationLatitude) / 2.0), 2.0) +
 | |
|                                         (Math.Cos(ToRadian(originLatitude)) * Math.Cos(ToRadian(destinationLatitude)) *
 | |
|                                         Math.Pow(Math.Sin(DiffRadian(originLongitude, destinationLongitude) / 2.0),
 | |
|                                                  2.0))))), decimalPlaces);
 | |
|     }
 | |
| 
 | |
|     private static double ParseValueFromDmsString(string value)
 | |
|     {
 | |
|         double result;
 | |
|         if (string.IsNullOrEmpty(value))
 | |
|             return double.MinValue;
 | |
| 
 | |
|         double secondsValue;
 | |
|         string[] degrees = value.Split('°');
 | |
|         if (degrees.Length != 2)
 | |
|             return double.MinValue;
 | |
|         if (!double.TryParse(degrees[0], out double degreesValue))
 | |
|             return double.MinValue;
 | |
| 
 | |
|         string[] minutes = degrees[1].Split('\'');
 | |
|         if (minutes.Length != 2)
 | |
|             return double.MinValue;
 | |
|         if (!double.TryParse(minutes[0], out double minutesValue))
 | |
|             return double.MinValue;
 | |
| 
 | |
|         string[] seconds = minutes[1].Split('"');
 | |
|         if (seconds.Length != 2)
 | |
|             secondsValue = 0;
 | |
|         else
 | |
|         {
 | |
|             if (!double.TryParse(seconds[0], out secondsValue))
 | |
|                 return double.MinValue;
 | |
|         }
 | |
|         result = Math.Abs(degreesValue) + (minutesValue / 60) + (secondsValue / 3600);
 | |
| 
 | |
|         if (degreesValue < 0)
 | |
|             result *= -1;
 | |
| 
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     internal static GeoLocation? GeoLocation(GpsDirectory[]? gpsDirectories)
 | |
|     {
 | |
|         GeoLocation? result = null;
 | |
|         if (gpsDirectories is not null)
 | |
|         {
 | |
|             foreach (GpsDirectory gpsDirectory in gpsDirectories)
 | |
|             {
 | |
|                 if (string.IsNullOrEmpty(gpsDirectory?.Latitude))
 | |
|                     result = null;
 | |
|                 else
 | |
|                 {
 | |
|                     string latitudeDMS = gpsDirectory.Latitude;
 | |
|                     double latitude = ParseValueFromDmsString(latitudeDMS);
 | |
|                     if (string.IsNullOrEmpty(gpsDirectory.Longitude))
 | |
|                         result = null;
 | |
|                     else
 | |
|                     {
 | |
|                         string longitudeDMS = gpsDirectory.Longitude;
 | |
|                         double longitude = ParseValueFromDmsString(longitudeDMS);
 | |
|                         result = new(latitude, longitude);
 | |
|                         string dms = result.ToDmsString();
 | |
|                         if ($"{latitudeDMS}, {longitudeDMS}" != dms)
 | |
|                             result = null;
 | |
|                     }
 | |
|                 }
 | |
|                 if (result is not null)
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
| } |