using View_by_Distance.Metadata.Models.Stateless.Methods; namespace View_by_Distance.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(ReadOnlyDictionary metadataExtractorDirectories) // { // GeoLocation? result; // if (!metadataExtractorDirectories.TryGetValue("GPS", out MetadataExtractorDirectory? metadataExtractorDirectory)) // result = null; // else // { // MetadataExtractorTag? metadataExtractorTag; // if (!metadataExtractorDirectory.Tags.TryGetValue((int)Shared.Models.Stateless.IExif.Tags.GPSLatitude, out metadataExtractorTag) || string.IsNullOrEmpty(metadataExtractorTag.Description)) // result = null; // else // { // string latitudeDMS = metadataExtractorTag.Description; // double latitude = ParseValueFromDmsString(latitudeDMS); // if (!metadataExtractorDirectory.Tags.TryGetValue((int)Shared.Models.Stateless.IExif.Tags.GPSLongitude, out metadataExtractorTag) || string.IsNullOrEmpty(metadataExtractorTag.Description)) // result = null; // else // { // string longitudeDMS = metadataExtractorTag.Description; // double longitude = ParseValueFromDmsString(longitudeDMS); // result = new(latitude, longitude); // string dms = result.ToDmsString(); // if ($"{latitudeDMS}, {longitudeDMS}" != dms) // result = null; // } // } // } // return result; // } }